summaryrefslogtreecommitdiff
path: root/inc
diff options
context:
space:
mode:
authorAndreas Gohr <andi@splitbrain.org>2013-02-03 22:57:45 +0100
committerAndreas Gohr <andi@splitbrain.org>2013-02-03 22:57:45 +0100
commit3da7921f08ecdda929466921ecc50698f1adf99e (patch)
tree0e179e504399e874bfd785d0a95eec44b76d5952 /inc
parent6cf2bbfa12b776cf47cb69ae40fb8862f715ad01 (diff)
parentcc4bb766fdac23358d7b586aa3830b9650eed7a8 (diff)
downloadrpg-3da7921f08ecdda929466921ecc50698f1adf99e.tar.gz
rpg-3da7921f08ecdda929466921ecc50698f1adf99e.tar.bz2
Merge branch 'master' into future
* master: (162 commits) fixed revision JS for images upgraded SimplePie to 1.3.1 FS#2708 removed obsolete browser plugin (migrate does it) adjust spacing to match standard 1.4em grid added comment on use of whitelist vs blacklist Updated idfilter() function for IIS use var and remove suggestions when needed Use variable for maximum number of suggestions for quicksearch. And hide suggestions when search field is emptied, or when no suggestion are found. added 'home' class to first link in hierarchical breadcrumbs reduced required max width to go into tablet mode re-added linear gradients for firefox added missing styling for disabled form elements (FS#2705) fixed acronyms in italics (FS#2684) improved print styles (includes fixes for FS#2645 and FS#2707) basic styles improvements Greek language update Use list in acl help text, for more structure Galician language update touch the config on save, even if no changes were made unwind the width narrowing commit put some whitespace between form submit button and fieldset bottom border ... Conflicts: lib/plugins/config/admin.php lib/plugins/config/settings/config.class.php
Diffstat (limited to 'inc')
-rw-r--r--inc/FeedParser.php8
-rw-r--r--inc/HTTPClient.php66
-rw-r--r--inc/Mailer.class.php1
-rw-r--r--inc/PassHash.class.php68
-rw-r--r--inc/RemoteAPICore.php14
-rw-r--r--inc/SimplePie.php16545
-rw-r--r--inc/Tar.class.php634
-rw-r--r--inc/TarLib.class.php918
-rw-r--r--inc/actions.php22
-rw-r--r--inc/auth.php35
-rw-r--r--inc/changelog.php1
-rw-r--r--inc/common.php90
-rw-r--r--inc/farm.php2
-rw-r--r--inc/fulltext.php15
-rw-r--r--inc/geshi.php68
-rw-r--r--inc/html.php36
-rw-r--r--inc/indexer.php230
-rw-r--r--inc/infoutils.php7
-rw-r--r--inc/lang/ar/lang.php2
-rw-r--r--inc/lang/ar/mailwrap.html13
-rw-r--r--inc/lang/ar/subscr_single.txt2
-rw-r--r--inc/lang/az/lang.php4
-rw-r--r--inc/lang/bg/lang.php6
-rw-r--r--inc/lang/bg/subscr_single.txt2
-rw-r--r--inc/lang/ca-valencia/lang.php4
-rw-r--r--inc/lang/ca/lang.php125
-rw-r--r--inc/lang/ca/mailwrap.html13
-rw-r--r--inc/lang/ca/resetpwd.txt3
-rw-r--r--inc/lang/ca/subscr_digest.txt21
-rw-r--r--inc/lang/ca/subscr_form.txt3
-rw-r--r--inc/lang/ca/subscr_list.txt21
-rw-r--r--inc/lang/cs/lang.php6
-rw-r--r--inc/lang/da/lang.php4
-rw-r--r--inc/lang/da/subscr_single.txt2
-rw-r--r--inc/lang/de-informal/install.html8
-rw-r--r--inc/lang/de-informal/lang.php39
-rw-r--r--inc/lang/de-informal/subscr_single.txt2
-rw-r--r--inc/lang/de/install.html8
-rw-r--r--inc/lang/de/lang.php39
-rw-r--r--inc/lang/de/subscr_single.txt2
-rw-r--r--inc/lang/el/lang.php21
-rw-r--r--inc/lang/el/mailwrap.html13
-rw-r--r--inc/lang/el/resetpwd.txt3
-rw-r--r--inc/lang/en/lang.php7
-rw-r--r--inc/lang/en/subscr_single.txt2
-rw-r--r--inc/lang/eo/lang.php4
-rw-r--r--inc/lang/eo/subscr_single.txt2
-rw-r--r--inc/lang/es/lang.php4
-rw-r--r--inc/lang/et/lang.php4
-rw-r--r--inc/lang/eu/lang.php4
-rw-r--r--inc/lang/fa/lang.php4
-rw-r--r--inc/lang/fi/lang.php4
-rw-r--r--inc/lang/fr/admin.txt3
-rw-r--r--inc/lang/fr/adminplugins.txt2
-rw-r--r--inc/lang/fr/backlinks.txt2
-rw-r--r--inc/lang/fr/conflict.txt4
-rw-r--r--inc/lang/fr/diff.txt2
-rw-r--r--inc/lang/fr/draft.txt4
-rw-r--r--inc/lang/fr/edit.txt2
-rw-r--r--inc/lang/fr/index.txt4
-rw-r--r--inc/lang/fr/install.html10
-rw-r--r--inc/lang/fr/lang.php174
-rw-r--r--inc/lang/fr/locked.txt2
-rw-r--r--inc/lang/fr/mailtext.txt2
-rw-r--r--inc/lang/fr/mailwrap.html2
-rw-r--r--inc/lang/fr/newpage.txt2
-rw-r--r--inc/lang/fr/norev.txt2
-rw-r--r--inc/lang/fr/password.txt2
-rw-r--r--inc/lang/fr/preview.txt2
-rw-r--r--inc/lang/fr/pwconfirm.txt8
-rw-r--r--inc/lang/fr/read.txt2
-rw-r--r--inc/lang/fr/register.txt2
-rw-r--r--inc/lang/fr/registermail.txt6
-rw-r--r--inc/lang/fr/resendpwd.txt2
-rw-r--r--inc/lang/fr/stopwords.txt4
-rw-r--r--inc/lang/fr/subscr_digest.txt4
-rw-r--r--inc/lang/fr/subscr_form.txt2
-rw-r--r--inc/lang/fr/subscr_list.txt2
-rw-r--r--inc/lang/fr/subscr_single.txt4
-rw-r--r--inc/lang/fr/uploadmail.txt4
-rw-r--r--inc/lang/gl/lang.php11
-rw-r--r--inc/lang/gl/mailwrap.html13
-rw-r--r--inc/lang/gl/resetpwd.txt3
-rw-r--r--inc/lang/he/lang.php4
-rw-r--r--inc/lang/he/subscr_single.txt2
-rw-r--r--inc/lang/hr/lang.php4
-rw-r--r--inc/lang/hu/lang.php4
-rw-r--r--inc/lang/ia/lang.php4
-rw-r--r--inc/lang/ia/subscr_single.txt2
-rw-r--r--inc/lang/id/lang.php4
-rw-r--r--inc/lang/it/lang.php4
-rw-r--r--inc/lang/it/subscr_single.txt2
-rw-r--r--inc/lang/ja/lang.php4
-rw-r--r--inc/lang/ko/lang.php4
-rw-r--r--inc/lang/ko/subscr_single.txt2
-rw-r--r--inc/lang/la/lang.php4
-rw-r--r--inc/lang/la/subscr_digest.txt2
-rw-r--r--inc/lang/la/subscr_single.txt2
-rw-r--r--inc/lang/lv/lang.php4
-rw-r--r--inc/lang/mk/lang.php4
-rw-r--r--inc/lang/mr/lang.php4
-rw-r--r--inc/lang/ne/lang.php4
-rw-r--r--inc/lang/nl/lang.php4
-rw-r--r--inc/lang/no/lang.php4
-rw-r--r--inc/lang/no/subscr_digest.txt2
-rw-r--r--inc/lang/no/subscr_list.txt2
-rw-r--r--inc/lang/no/subscr_single.txt2
-rw-r--r--inc/lang/pl/lang.php4
-rw-r--r--inc/lang/pt-br/lang.php4
-rw-r--r--inc/lang/pt/lang.php4
-rw-r--r--inc/lang/pt/subscr_single.txt2
-rw-r--r--inc/lang/ro/lang.php4
-rw-r--r--inc/lang/ru/lang.php4
-rw-r--r--inc/lang/sk/lang.php4
-rw-r--r--inc/lang/sl/lang.php4
-rw-r--r--inc/lang/sq/lang.php4
-rw-r--r--inc/lang/sq/subscr_single.txt2
-rw-r--r--inc/lang/sr/lang.php4
-rw-r--r--inc/lang/sv/lang.php6
-rw-r--r--inc/lang/tr/lang.php51
-rw-r--r--inc/lang/tr/resetpwd.txt3
-rw-r--r--inc/lang/uk/lang.php4
-rw-r--r--inc/lang/zh-tw/adminplugins.txt2
-rw-r--r--inc/lang/zh-tw/backlinks.txt2
-rw-r--r--inc/lang/zh-tw/diff.txt2
-rw-r--r--inc/lang/zh-tw/edit.txt2
-rw-r--r--inc/lang/zh-tw/editrev.txt2
-rw-r--r--inc/lang/zh-tw/index.txt2
-rw-r--r--inc/lang/zh-tw/install.html6
-rw-r--r--inc/lang/zh-tw/lang.php97
-rw-r--r--inc/lang/zh-tw/locked.txt2
-rw-r--r--inc/lang/zh-tw/login.txt3
-rw-r--r--inc/lang/zh-tw/mailtext.txt2
-rw-r--r--inc/lang/zh-tw/norev.txt2
-rw-r--r--inc/lang/zh-tw/preview.txt2
-rw-r--r--inc/lang/zh-tw/pwconfirm.txt8
-rw-r--r--inc/lang/zh-tw/read.txt2
-rw-r--r--inc/lang/zh-tw/register.txt3
-rw-r--r--inc/lang/zh-tw/registermail.txt4
-rw-r--r--inc/lang/zh-tw/resendpwd.txt2
-rw-r--r--inc/lang/zh-tw/revisions.txt2
-rw-r--r--inc/lang/zh-tw/stopwords.txt10
-rw-r--r--inc/lang/zh-tw/subscr_digest.txt6
-rw-r--r--inc/lang/zh-tw/subscr_form.txt2
-rw-r--r--inc/lang/zh-tw/subscr_list.txt6
-rw-r--r--inc/lang/zh-tw/subscr_single.txt6
-rw-r--r--inc/lang/zh-tw/updateprofile.txt2
-rw-r--r--inc/lang/zh-tw/uploadmail.txt4
-rw-r--r--inc/lang/zh/lang.php4
-rw-r--r--inc/load.php2
-rw-r--r--inc/media.php23
-rw-r--r--inc/pageutils.php6
-rw-r--r--inc/parser/renderer.php5
-rw-r--r--inc/parser/xhtml.php7
-rw-r--r--inc/plugin.php10
-rw-r--r--inc/search.php30
-rw-r--r--inc/subscription.php993
-rw-r--r--inc/template.php8
-rw-r--r--inc/utf8.php19
159 files changed, 12048 insertions, 8873 deletions
diff --git a/inc/FeedParser.php b/inc/FeedParser.php
index e5f1fb636..96d32e83f 100644
--- a/inc/FeedParser.php
+++ b/inc/FeedParser.php
@@ -15,8 +15,8 @@ class FeedParser extends SimplePie {
/**
* Constructor. Set some defaults
*/
- function FeedParser(){
- $this->SimplePie();
+ function __construct(){
+ parent::__construct();
$this->enable_cache(false);
$this->set_file_class('FeedParser_File');
}
@@ -47,8 +47,8 @@ class FeedParser_File extends SimplePie_File {
*
* We ignore all given parameters - they are set in DokuHTTPClient
*/
- function FeedParser_File($url, $timeout=10, $redirects=5,
- $headers=null, $useragent=null, $force_fsockopen=false) {
+ function __construct($url, $timeout=10, $redirects=5,
+ $headers=null, $useragent=null, $force_fsockopen=false) {
$this->http = new DokuHTTPClient();
$this->success = $this->http->sendRequest($url);
diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php
index c4cfcbf7c..51c1de875 100644
--- a/inc/HTTPClient.php
+++ b/inc/HTTPClient.php
@@ -254,11 +254,7 @@ class HTTPClient {
if(!empty($uri['port'])) $headers['Host'].= ':'.$uri['port'];
$headers['User-Agent'] = $this->agent;
$headers['Referer'] = $this->referer;
- if ($this->keep_alive) {
- $headers['Connection'] = 'Keep-Alive';
- } else {
- $headers['Connection'] = 'Close';
- }
+
if($method == 'POST'){
if(is_array($data)){
if($headers['Content-Type'] == 'multipart/form-data'){
@@ -299,6 +295,14 @@ class HTTPClient {
return false;
}
+ // try establish a CONNECT tunnel for SSL
+ if($this->_ssltunnel($socket, $request_url)){
+ // no keep alive for tunnels
+ $this->keep_alive = false;
+ // tunnel is authed already
+ if(isset($headers['Proxy-Authentication'])) unset($headers['Proxy-Authentication']);
+ }
+
// keep alive?
if ($this->keep_alive) {
self::$connections[$connectionId] = $socket;
@@ -307,6 +311,15 @@ class HTTPClient {
}
}
+ if ($this->keep_alive && !$this->proxy_host) {
+ // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
+ // connection token to a proxy server. We still do keep the connection the
+ // proxy alive (well except for CONNECT tunnels)
+ $headers['Connection'] = 'Keep-Alive';
+ } else {
+ $headers['Connection'] = 'Close';
+ }
+
try {
//set non-blocking
stream_set_blocking($socket, false);
@@ -485,6 +498,49 @@ class HTTPClient {
}
/**
+ * Tries to establish a CONNECT tunnel via Proxy
+ *
+ * Protocol, Servername and Port will be stripped from the request URL when a successful CONNECT happened
+ *
+ * @param ressource &$socket
+ * @param string &$requesturl
+ * @return bool true if a tunnel was established
+ */
+ function _ssltunnel(&$socket, &$requesturl){
+ if(!$this->proxy_host) return false;
+ $requestinfo = parse_url($requesturl);
+ if($requestinfo['scheme'] != 'https') return false;
+ if(!$requestinfo['port']) $requestinfo['port'] = 443;
+
+ // build request
+ $request = "CONNECT {$requestinfo['host']}:{$requestinfo['port']} HTTP/1.0".HTTP_NL;
+ $request .= "Host: {$requestinfo['host']}".HTTP_NL;
+ if($this->proxy_user) {
+ 'Proxy-Authorization Basic '.base64_encode($this->proxy_user.':'.$this->proxy_pass).HTTP_NL;
+ }
+ $request .= HTTP_NL;
+
+ $this->_debug('SSL Tunnel CONNECT',$request);
+ $this->_sendData($socket, $request, 'SSL Tunnel CONNECT');
+
+ // read headers from socket
+ $r_headers = '';
+ do{
+ $r_line = $this->_readLine($socket, 'headers');
+ $r_headers .= $r_line;
+ }while($r_line != "\r\n" && $r_line != "\n");
+
+ $this->_debug('SSL Tunnel Response',$r_headers);
+ if(preg_match('/^HTTP\/1\.0 200/i',$r_headers)){
+ if (stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv3_CLIENT)) {
+ $requesturl = $requestinfo['path'];
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Safely write data to a socket
*
* @param handle $socket An open socket handle
diff --git a/inc/Mailer.class.php b/inc/Mailer.class.php
index cbd1eb0a9..f1492be9b 100644
--- a/inc/Mailer.class.php
+++ b/inc/Mailer.class.php
@@ -555,6 +555,7 @@ class Mailer {
protected function prepareHeaders() {
$headers = '';
foreach($this->headers as $key => $val) {
+ if ($val === '') continue;
$headers .= "$key: $val".MAILHEADER_EOL;
}
return $headers;
diff --git a/inc/PassHash.class.php b/inc/PassHash.class.php
index 13be479cc..080fb4778 100644
--- a/inc/PassHash.class.php
+++ b/inc/PassHash.class.php
@@ -4,7 +4,7 @@
*
* This class implements various mechanisms used to hash passwords
*
- * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Andreas Gohr <andi@splitbrain.org>
* @license LGPL2
*/
class PassHash {
@@ -58,6 +58,12 @@ class PassHash {
} elseif(substr($hash, 0, 6) == '{SMD5}') {
$method = 'lsmd5';
$salt = substr(base64_decode(substr($hash, 6)), 16);
+ } elseif(preg_match('/^:B:(.+?):.{32}$/', $hash, $m)) {
+ $method = 'mediawiki';
+ $salt = $m[1];
+ } elseif(preg_match('/^\$6\$(.+?)\$/', $hash, $m)) {
+ $method = 'sha512';
+ $salt = $m[1];
} elseif($len == 32) {
$method = 'md5';
} elseif($len == 40) {
@@ -101,14 +107,18 @@ class PassHash {
* Initialize the passed variable with a salt if needed.
*
* If $salt is not null, the value is kept, but the lenght restriction is
- * applied.
+ * applied (unless, $cut is false).
*
* @param string &$salt The salt, pass null if you want one generated
- * @param int $len The length of the salt
+ * @param int $len The length of the salt
+ * @param bool $cut Apply length restriction to existing salt?
*/
- public function init_salt(&$salt, $len = 32) {
- if(is_null($salt)) $salt = $this->gen_salt($len);
- if(strlen($salt) > $len) $salt = substr($salt, 0, $len);
+ public function init_salt(&$salt, $len = 32, $cut = true) {
+ if(is_null($salt)) {
+ $salt = $this->gen_salt($len);
+ $cut = true; // for new hashes we alway apply length restriction
+ }
+ if(strlen($salt) > $len && $cut) $salt = substr($salt, 0, $len);
}
// Password hashing methods follow below
@@ -263,7 +273,7 @@ class PassHash {
*
* This method was used by old MySQL systems
*
- * @link http://www.php.net/mysql
+ * @link http://www.php.net/mysql
* @author <soren at byu dot edu>
* @param string $clear The clear text to hash
* @return string Hashed password
@@ -327,9 +337,9 @@ class PassHash {
* an exception.
*
* @link http://www.openwall.com/phpass/
- * @param string $clear The clear text to hash
- * @param string $salt The salt to use, null for random
- * @param string $magic The hash identifier (P or H)
+ * @param string $clear The clear text to hash
+ * @param string $salt The salt to use, null for random
+ * @param string $magic The hash identifier (P or H)
* @param int $compute The iteration count for new passwords
* @throws Exception
* @return string Hashed password
@@ -430,8 +440,8 @@ class PassHash {
* will break. When no salt is given, the iteration count can be set
* through the $compute variable.
*
- * @param string $clear The clear text to hash
- * @param string $salt The salt to use, null for random
+ * @param string $clear The clear text to hash
+ * @param string $salt The salt to use, null for random
* @param int $compute The iteration count (between 4 and 31)
* @throws Exception
* @return string Hashed password
@@ -450,4 +460,38 @@ class PassHash {
return crypt($clear, $salt);
}
+ /**
+ * Password hashing method SHA512
+ *
+ * This is only supported on PHP 5.3.2 or higher and will throw an exception if
+ * the needed crypt support is not available
+ *
+ * @param string $clear The clear text to hash
+ * @param string $salt The salt to use, null for random
+ * @return string Hashed password
+ * @throws Exception
+ */
+ public function hash_sha512($clear, $salt = null) {
+ if(!defined('CRYPT_SHA512') || CRYPT_SHA512 != 1) {
+ throw new Exception('This PHP installation has no SHA512 support');
+ }
+ $this->init_salt($salt, 8, false);
+ return crypt($clear, '$6$'.$salt.'$');
+ }
+
+ /**
+ * Password hashing method 'mediawiki'
+ *
+ * Uses salted MD5, this is referred to as Method B in MediaWiki docs. Unsalted md5
+ * method 'A' is not supported.
+ *
+ * @link http://www.mediawiki.org/wiki/Manual_talk:User_table#user_password_column
+ * @param string $clear The clear text to hash
+ * @param string $salt The salt to use, null for random
+ * @return string Hashed password
+ */
+ public function hash_mediawiki($clear, $salt = null) {
+ $this->init_salt($salt, 8, false);
+ return ':B:'.$salt.':'.md5($salt.'-'.md5($clear));
+ }
}
diff --git a/inc/RemoteAPICore.php b/inc/RemoteAPICore.php
index 36c518881..81b211ec8 100644
--- a/inc/RemoteAPICore.php
+++ b/inc/RemoteAPICore.php
@@ -3,7 +3,7 @@
/**
* Increased whenever the API is changed
*/
-define('DOKU_API_VERSION', 7);
+define('DOKU_API_VERSION', 8);
class RemoteAPICore {
@@ -48,7 +48,7 @@ class RemoteAPICore {
'public' => '1'
), 'dokuwiki.appendPage' => array(
'args' => array('string', 'string', 'array'),
- 'return' => 'int',
+ 'return' => 'bool',
'doc' => 'Append text to a wiki page.'
), 'wiki.getPage' => array(
'args' => array('string'),
@@ -102,7 +102,7 @@ class RemoteAPICore {
'name' => 'pageVersions'
), 'wiki.putPage' => array(
'args' => array('string', 'string', 'array'),
- 'return' => 'int',
+ 'return' => 'bool',
'doc' => 'Saves a wiki page.'
), 'wiki.listLinks' => array(
'args' => array('string'),
@@ -344,6 +344,8 @@ class RemoteAPICore {
for($i=0; $i<$len; $i++) {
unset($data[$i]['meta']);
+ $data[$i]['perms'] = $data[$i]['perm'];
+ unset($data[$i]['perm']);
$data[$i]['lastModified'] = $this->api->toDate($data[$i]['mtime']);
}
return $data;
@@ -440,7 +442,7 @@ class RemoteAPICore {
// run the indexer if page wasn't indexed yet
idx_addPage($id);
- return 0;
+ return true;
}
/**
@@ -654,7 +656,9 @@ class RemoteAPICore {
if(count($revisions)>0 && $first==0) {
array_unshift($revisions, ''); // include current revision
- array_pop($revisions); // remove extra log entry
+ if ( count($revisions) > $conf['recent'] ){
+ array_pop($revisions); // remove extra log entry
+ }
}
if(count($revisions) > $conf['recent']) {
diff --git a/inc/SimplePie.php b/inc/SimplePie.php
index 10d8141bd..fd69b4b09 100644
--- a/inc/SimplePie.php
+++ b/inc/SimplePie.php
@@ -5,7 +5,10 @@
* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
*
- * Copyright (c) 2004-2011, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * Please note: This file is automatically generated by a build script. The
+ * full original source is always available from http://simplepie.org/
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
@@ -33,15 +36,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.2.1
- * @copyright 2004-2011 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
* @author Ryan McCue
* @link http://simplepie.org/ SimplePie
- * @link http://simplepie.org/support/ Please submit all bug reports and feature requests to the SimplePie forums
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @todo phpDoc comments
*/
/**
@@ -52,12 +53,13 @@ define('SIMPLEPIE_NAME', 'SimplePie');
/**
* SimplePie Version
*/
-define('SIMPLEPIE_VERSION', '1.2.1-dev');
+define('SIMPLEPIE_VERSION', '1.3.1');
/**
* SimplePie Build
+ * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
*/
-define('SIMPLEPIE_BUILD', '20111015034325');
+define('SIMPLEPIE_BUILD', '20121030175911');
/**
* SimplePie Website URL
@@ -334,11 +336,31 @@ define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
/**
- * Wrong Media RSS Namespace
+ * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
*/
define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
/**
+ * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
+
+/**
+ * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
+
+/**
+ * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
+
+/**
+ * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
+
+/**
* iTunes RSS Namespace
*/
define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
@@ -354,11 +376,6 @@ define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
/**
- * Whether we're running on PHP5
- */
-define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>='));
-
-/**
* No file source
*/
define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
@@ -392,6 +409,7 @@ define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
* SimplePie
*
* @package SimplePie
+ * @subpackage API
*/
class SimplePie
{
@@ -399,55 +417,55 @@ class SimplePie
* @var array Raw data
* @access private
*/
- var $data = array();
+ public $data = array();
/**
* @var mixed Error string
* @access private
*/
- var $error;
+ public $error;
/**
* @var object Instance of SimplePie_Sanitize (or other class)
* @see SimplePie::set_sanitize_class()
* @access private
*/
- var $sanitize;
+ public $sanitize;
/**
* @var string SimplePie Useragent
* @see SimplePie::set_useragent()
* @access private
*/
- var $useragent = SIMPLEPIE_USERAGENT;
+ public $useragent = SIMPLEPIE_USERAGENT;
/**
* @var string Feed URL
* @see SimplePie::set_feed_url()
* @access private
*/
- var $feed_url;
+ public $feed_url;
/**
* @var object Instance of SimplePie_File to use as a feed
* @see SimplePie::set_file()
* @access private
*/
- var $file;
+ public $file;
/**
* @var string Raw feed data
* @see SimplePie::set_raw_data()
* @access private
*/
- var $raw_data;
+ public $raw_data;
/**
* @var int Timeout for fetching remote files
* @see SimplePie::set_timeout()
* @access private
*/
- var $timeout = 10;
+ public $timeout = 10;
/**
* @var bool Forces fsockopen() to be used for remote files instead
@@ -455,7 +473,7 @@ class SimplePie
* @see SimplePie::force_fsockopen()
* @access private
*/
- var $force_fsockopen = false;
+ public $force_fsockopen = false;
/**
* @var bool Force the given data/URL to be treated as a feed no matter what
@@ -463,56 +481,49 @@ class SimplePie
* @see SimplePie::force_feed()
* @access private
*/
- var $force_feed = false;
-
- /**
- * @var bool Enable/Disable XML dump
- * @see SimplePie::enable_xml_dump()
- * @access private
- */
- var $xml_dump = false;
+ public $force_feed = false;
/**
* @var bool Enable/Disable Caching
* @see SimplePie::enable_cache()
* @access private
*/
- var $cache = true;
+ public $cache = true;
/**
* @var int Cache duration (in seconds)
* @see SimplePie::set_cache_duration()
* @access private
*/
- var $cache_duration = 3600;
+ public $cache_duration = 3600;
/**
* @var int Auto-discovery cache duration (in seconds)
* @see SimplePie::set_autodiscovery_cache_duration()
* @access private
*/
- var $autodiscovery_cache_duration = 604800; // 7 Days.
+ public $autodiscovery_cache_duration = 604800; // 7 Days.
/**
* @var string Cache location (relative to executing script)
* @see SimplePie::set_cache_location()
* @access private
*/
- var $cache_location = './cache';
+ public $cache_location = './cache';
/**
* @var string Function that creates the cache filename
* @see SimplePie::set_cache_name_function()
* @access private
*/
- var $cache_name_function = 'md5';
+ public $cache_name_function = 'md5';
/**
* @var bool Reorder feed by date descending
* @see SimplePie::enable_order_by_date()
* @access private
*/
- var $order_by_date = true;
+ public $order_by_date = true;
/**
* @var mixed Force input encoding to be set to the follow value
@@ -520,246 +531,132 @@ class SimplePie
* @see SimplePie::set_input_encoding()
* @access private
*/
- var $input_encoding = false;
+ public $input_encoding = false;
/**
* @var int Feed Autodiscovery Level
* @see SimplePie::set_autodiscovery_level()
* @access private
*/
- var $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
-
- /**
- * @var string Class used for caching feeds
- * @see SimplePie::set_cache_class()
- * @access private
- */
- var $cache_class = 'SimplePie_Cache';
-
- /**
- * @var string Class used for locating feeds
- * @see SimplePie::set_locator_class()
- * @access private
- */
- var $locator_class = 'SimplePie_Locator';
-
- /**
- * @var string Class used for parsing feeds
- * @see SimplePie::set_parser_class()
- * @access private
- */
- var $parser_class = 'SimplePie_Parser';
-
- /**
- * @var string Class used for fetching feeds
- * @see SimplePie::set_file_class()
- * @access private
- */
- var $file_class = 'SimplePie_File';
-
- /**
- * @var string Class used for items
- * @see SimplePie::set_item_class()
- * @access private
- */
- var $item_class = 'SimplePie_Item';
-
- /**
- * @var string Class used for authors
- * @see SimplePie::set_author_class()
- * @access private
- */
- var $author_class = 'SimplePie_Author';
-
- /**
- * @var string Class used for categories
- * @see SimplePie::set_category_class()
- * @access private
- */
- var $category_class = 'SimplePie_Category';
-
- /**
- * @var string Class used for enclosures
- * @see SimplePie::set_enclosures_class()
- * @access private
- */
- var $enclosure_class = 'SimplePie_Enclosure';
-
- /**
- * @var string Class used for Media RSS <media:text> captions
- * @see SimplePie::set_caption_class()
- * @access private
- */
- var $caption_class = 'SimplePie_Caption';
-
- /**
- * @var string Class used for Media RSS <media:copyright>
- * @see SimplePie::set_copyright_class()
- * @access private
- */
- var $copyright_class = 'SimplePie_Copyright';
-
- /**
- * @var string Class used for Media RSS <media:credit>
- * @see SimplePie::set_credit_class()
- * @access private
- */
- var $credit_class = 'SimplePie_Credit';
-
- /**
- * @var string Class used for Media RSS <media:rating>
- * @see SimplePie::set_rating_class()
- * @access private
- */
- var $rating_class = 'SimplePie_Rating';
+ public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
/**
- * @var string Class used for Media RSS <media:restriction>
- * @see SimplePie::set_restriction_class()
- * @access private
- */
- var $restriction_class = 'SimplePie_Restriction';
-
- /**
- * @var string Class used for content-type sniffing
- * @see SimplePie::set_content_type_sniffer_class()
- * @access private
- */
- var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
-
- /**
- * @var string Class used for item sources.
- * @see SimplePie::set_source_class()
- * @access private
- */
- var $source_class = 'SimplePie_Source';
-
- /**
- * @var mixed Set javascript query string parameter (false, or
- * anything type-cast to false, disables this feature)
- * @see SimplePie::set_javascript()
- * @access private
+ * Class registry object
+ *
+ * @var SimplePie_Registry
*/
- var $javascript = 'js';
+ public $registry;
/**
* @var int Maximum number of feeds to check with autodiscovery
* @see SimplePie::set_max_checked_feeds()
* @access private
*/
- var $max_checked_feeds = 10;
+ public $max_checked_feeds = 10;
/**
* @var array All the feeds found during the autodiscovery process
* @see SimplePie::get_all_discovered_feeds()
* @access private
*/
- var $all_discovered_feeds = array();
-
- /**
- * @var string Web-accessible path to the handler_favicon.php file.
- * @see SimplePie::set_favicon_handler()
- * @access private
- */
- var $favicon_handler = '';
+ public $all_discovered_feeds = array();
/**
* @var string Web-accessible path to the handler_image.php file.
* @see SimplePie::set_image_handler()
* @access private
*/
- var $image_handler = '';
+ public $image_handler = '';
/**
* @var array Stores the URLs when multiple feeds are being initialized.
* @see SimplePie::set_feed_url()
* @access private
*/
- var $multifeed_url = array();
+ public $multifeed_url = array();
/**
* @var array Stores SimplePie objects when multiple feeds initialized.
* @access private
*/
- var $multifeed_objects = array();
+ public $multifeed_objects = array();
/**
* @var array Stores the get_object_vars() array for use with multifeeds.
* @see SimplePie::set_feed_url()
* @access private
*/
- var $config_settings = null;
+ public $config_settings = null;
/**
* @var integer Stores the number of items to return per-feed with multifeeds.
* @see SimplePie::set_item_limit()
* @access private
*/
- var $item_limit = 0;
+ public $item_limit = 0;
/**
* @var array Stores the default attributes to be stripped by strip_attributes().
* @see SimplePie::strip_attributes()
* @access private
*/
- var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+ public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
/**
* @var array Stores the default tags to be stripped by strip_htmltags().
* @see SimplePie::strip_htmltags()
* @access private
*/
- var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
+ public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
/**
* The SimplePie class contains feed level data and options
*
- * There are two ways that you can create a new SimplePie object. The first
- * is by passing a feed URL as a parameter to the SimplePie constructor
- * (as well as optionally setting the cache location and cache expiry). This
- * will initialise the whole feed with all of the default settings, and you
- * can begin accessing methods and properties immediately.
- *
- * The second way is to create the SimplePie object with no parameters
- * at all. This will enable you to set configuration options. After setting
+ * To use SimplePie, create the SimplePie object with no parameters. You can
+ * then set configuration options using the provided methods. After setting
* them, you must initialise the feed using $feed->init(). At that point the
- * object's methods and properties will be available to you. This format is
- * what is used throughout this documentation.
+ * object's methods and properties will be available to you.
+ *
+ * Previously, it was possible to pass in the feed URL along with cache
+ * options directly into the constructor. This has been removed as of 1.3 as
+ * it caused a lot of confusion.
*
- * @access public
* @since 1.0 Preview Release
- * @param string $feed_url This is the URL you want to parse.
- * @param string $cache_location This is where you want the cache to be stored.
- * @param int $cache_duration This is the number of seconds that you want to store the cache file for.
*/
- function SimplePie($feed_url = null, $cache_location = null, $cache_duration = null)
+ public function __construct()
{
- // Other objects, instances created here so we can set options on them
- $this->sanitize = new SimplePie_Sanitize;
-
- // Set options if they're passed to the constructor
- if ($cache_location !== null)
+ if (version_compare(PHP_VERSION, '5.2', '<'))
{
- $this->set_cache_location($cache_location);
+ trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
+ die();
}
- if ($cache_duration !== null)
- {
- $this->set_cache_duration($cache_duration);
- }
+ // Other objects, instances created here so we can set options on them
+ $this->sanitize = new SimplePie_Sanitize();
+ $this->registry = new SimplePie_Registry();
- // Only init the script if we're passed a feed URL
- if ($feed_url !== null)
+ if (func_num_args() > 0)
{
- $this->set_feed_url($feed_url);
- $this->init();
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
+
+ $args = func_get_args();
+ switch (count($args)) {
+ case 3:
+ $this->set_cache_duration($args[2]);
+ case 2:
+ $this->set_cache_location($args[1]);
+ case 1:
+ $this->set_feed_url($args[0]);
+ $this->init();
+ }
}
}
/**
* Used for converting object to a string
*/
- function __toString()
+ public function __toString()
{
return md5(serialize($this->data));
}
@@ -767,7 +664,7 @@ class SimplePie
/**
* Remove items that link back to this before destroying this object
*/
- function __destruct()
+ public function __destruct()
{
if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
{
@@ -791,20 +688,21 @@ class SimplePie
}
/**
- * Force the given data/URL to be treated as a feed no matter what it
- * appears like
+ * Force the given data/URL to be treated as a feed
+ *
+ * This tells SimplePie to ignore the content-type provided by the server.
+ * Be careful when using this option, as it will also disable autodiscovery.
*
- * @access public
* @since 1.1
* @param bool $enable Force the given data/URL to be treated as a feed
*/
- function force_feed($enable = false)
+ public function force_feed($enable = false)
{
$this->force_feed = (bool) $enable;
}
/**
- * This is the URL of the feed you want to parse.
+ * Set the URL of the feed you want to parse
*
* This allows you to enter the URL of the feed you want to parse, or the
* website you want to try to use auto-discovery on. This takes priority
@@ -814,37 +712,35 @@ class SimplePie
* of a string for the $url. Remember that with each additional feed comes
* additional processing and resources.
*
- * @access public
* @since 1.0 Preview Release
- * @param mixed $url This is the URL (or array of URLs) that you want to parse.
- * @see SimplePie::set_raw_data()
+ * @see set_raw_data()
+ * @param string|array $url This is the URL (or array of URLs) that you want to parse.
*/
- function set_feed_url($url)
+ public function set_feed_url($url)
{
+ $this->multifeed_url = array();
if (is_array($url))
{
- $this->multifeed_url = array();
foreach ($url as $value)
{
- $this->multifeed_url[] = SimplePie_Misc::fix_protocol($value, 1);
+ $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
}
}
else
{
- $this->feed_url = SimplePie_Misc::fix_protocol($url, 1);
+ $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
}
}
/**
- * Provides an instance of SimplePie_File to use as a feed
+ * Set an instance of {@see SimplePie_File} to use as a feed
*
- * @access public
- * @param object &$file Instance of SimplePie_File (or subclass)
+ * @param SimplePie_File &$file
* @return bool True on success, false on failure
*/
- function set_file(&$file)
+ public function set_file(&$file)
{
- if (is_a($file, 'SimplePie_File'))
+ if ($file instanceof SimplePie_File)
{
$this->feed_url = $file->url;
$this->file =& $file;
@@ -854,138 +750,113 @@ class SimplePie
}
/**
+ * Set the raw XML data to parse
+ *
* Allows you to use a string of RSS/Atom data instead of a remote feed.
*
* If you have a feed available as a string in PHP, you can tell SimplePie
* to parse that data string instead of a remote feed. Any set feed URL
* takes precedence.
*
- * @access public
* @since 1.0 Beta 3
* @param string $data RSS or Atom data as a string.
- * @see SimplePie::set_feed_url()
+ * @see set_feed_url()
*/
- function set_raw_data($data)
+ public function set_raw_data($data)
{
$this->raw_data = $data;
}
/**
- * Allows you to override the default timeout for fetching remote feeds.
+ * Set the the default timeout for fetching remote feeds
*
* This allows you to change the maximum time the feed's server to respond
* and send the feed back.
*
- * @access public
* @since 1.0 Beta 3
* @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
*/
- function set_timeout($timeout = 10)
+ public function set_timeout($timeout = 10)
{
$this->timeout = (int) $timeout;
}
/**
- * Forces SimplePie to use fsockopen() instead of the preferred cURL
- * functions.
+ * Force SimplePie to use fsockopen() instead of cURL
*
- * @access public
* @since 1.0 Beta 3
* @param bool $enable Force fsockopen() to be used
*/
- function force_fsockopen($enable = false)
+ public function force_fsockopen($enable = false)
{
$this->force_fsockopen = (bool) $enable;
}
/**
- * Outputs the raw XML content of the feed, after it has gone through
- * SimplePie's filters.
- *
- * Used only for debugging, this function will output the XML content as
- * text/xml. When SimplePie reads in a feed, it does a bit of cleaning up
- * before trying to parse it. Many parts of the feed are re-written in
- * memory, and in the end, you have a parsable feed. XML dump shows you the
- * actual XML that SimplePie tries to parse, which may or may not be very
- * different from the original feed.
- *
- * @access public
- * @since 1.0 Preview Release
- * @param bool $enable Enable XML dump
- */
- function enable_xml_dump($enable = false)
- {
- $this->xml_dump = (bool) $enable;
- }
-
- /**
- * Enables/disables caching in SimplePie.
+ * Enable/disable caching in SimplePie.
*
* This option allows you to disable caching all-together in SimplePie.
* However, disabling the cache can lead to longer load times.
*
- * @access public
* @since 1.0 Preview Release
* @param bool $enable Enable caching
*/
- function enable_cache($enable = true)
+ public function enable_cache($enable = true)
{
$this->cache = (bool) $enable;
}
/**
- * Set the length of time (in seconds) that the contents of a feed
- * will be cached.
+ * Set the length of time (in seconds) that the contents of a feed will be
+ * cached
*
- * @access public
- * @param int $seconds The feed content cache duration.
+ * @param int $seconds The feed content cache duration
*/
- function set_cache_duration($seconds = 3600)
+ public function set_cache_duration($seconds = 3600)
{
$this->cache_duration = (int) $seconds;
}
/**
- * Set the length of time (in seconds) that the autodiscovered feed
- * URL will be cached.
+ * Set the length of time (in seconds) that the autodiscovered feed URL will
+ * be cached
*
- * @access public
* @param int $seconds The autodiscovered feed URL cache duration.
*/
- function set_autodiscovery_cache_duration($seconds = 604800)
+ public function set_autodiscovery_cache_duration($seconds = 604800)
{
$this->autodiscovery_cache_duration = (int) $seconds;
}
/**
- * Set the file system location where the cached files should be stored.
+ * Set the file system location where the cached files should be stored
*
- * @access public
* @param string $location The file system location.
*/
- function set_cache_location($location = './cache')
+ public function set_cache_location($location = './cache')
{
$this->cache_location = (string) $location;
}
/**
- * Determines whether feed items should be sorted into reverse chronological order.
+ * Set whether feed items should be sorted into reverse chronological order
*
- * @access public
* @param bool $enable Sort as reverse chronological order.
*/
- function enable_order_by_date($enable = true)
+ public function enable_order_by_date($enable = true)
{
$this->order_by_date = (bool) $enable;
}
/**
- * Allows you to override the character encoding reported by the feed.
+ * Set the character encoding used to parse the feed
*
- * @access public
- * @param string $encoding Character encoding.
+ * This overrides the encoding reported by the feed, however it will fall
+ * back to the normal encoding detection if the override fails
+ *
+ * @param string $encoding Character encoding
*/
- function set_input_encoding($encoding = false)
+ public function set_input_encoding($encoding = false)
{
if ($encoding)
{
@@ -1000,7 +871,6 @@ class SimplePie
/**
* Set how much feed autodiscovery to do
*
- * @access public
* @see SIMPLEPIE_LOCATOR_NONE
* @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
* @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
@@ -1008,325 +878,168 @@ class SimplePie
* @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
* @see SIMPLEPIE_LOCATOR_REMOTE_BODY
* @see SIMPLEPIE_LOCATOR_ALL
- * @param int $level Feed Autodiscovery Level (level can be a
- * combination of the above constants, see bitwise OR operator)
+ * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
*/
- function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
+ public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
{
$this->autodiscovery = (int) $level;
}
/**
- * Allows you to change which class SimplePie uses for caching.
- * Useful when you are overloading or extending SimplePie's default classes.
+ * Get the class registry
*
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Use this to override SimplePie's default classes
+ * @see SimplePie_Registry
+ * @return SimplePie_Registry
*/
- function set_cache_class($class = 'SimplePie_Cache')
+ public function &get_registry()
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Cache'))
- {
- $this->cache_class = $class;
- return true;
- }
- return false;
+ return $this->registry;
}
- /**
- * Allows you to change which class SimplePie uses for auto-discovery.
+ /**#@+
* Useful when you are overloading or extending SimplePie's default classes.
*
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+ * @deprecated Use {@see get_registry()} instead
* @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * @param string $class Name of custom class
+ * @return boolean True on success, false otherwise
+ */
+ /**
+ * Set which class SimplePie uses for caching
*/
- function set_locator_class($class = 'SimplePie_Locator')
+ public function set_cache_class($class = 'SimplePie_Cache')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Locator'))
- {
- $this->locator_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Cache', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for XML parsing.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for auto-discovery
*/
- function set_parser_class($class = 'SimplePie_Parser')
+ public function set_locator_class($class = 'SimplePie_Locator')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser'))
- {
- $this->parser_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Locator', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for remote file fetching.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for XML parsing
*/
- function set_file_class($class = 'SimplePie_File')
+ public function set_parser_class($class = 'SimplePie_Parser')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_File'))
- {
- $this->file_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Parser', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for data sanitization.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for remote file fetching
*/
- function set_sanitize_class($class = 'SimplePie_Sanitize')
+ public function set_file_class($class = 'SimplePie_File')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize'))
- {
- $this->sanitize = new $class;
- return true;
- }
- return false;
+ return $this->registry->register('File', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for handling feed items.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for data sanitization
*/
- function set_item_class($class = 'SimplePie_Item')
+ public function set_sanitize_class($class = 'SimplePie_Sanitize')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item'))
- {
- $this->item_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Sanitize', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for handling author data.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for handling feed items
*/
- function set_author_class($class = 'SimplePie_Author')
+ public function set_item_class($class = 'SimplePie_Item')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author'))
- {
- $this->author_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Item', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for handling category data.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for handling author data
*/
- function set_category_class($class = 'SimplePie_Category')
+ public function set_author_class($class = 'SimplePie_Author')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category'))
- {
- $this->category_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Author', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for feed enclosures.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for handling category data
*/
- function set_enclosure_class($class = 'SimplePie_Enclosure')
+ public function set_category_class($class = 'SimplePie_Category')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure'))
- {
- $this->enclosure_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Category', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for <media:text> captions
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for feed enclosures
*/
- function set_caption_class($class = 'SimplePie_Caption')
+ public function set_enclosure_class($class = 'SimplePie_Enclosure')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Caption'))
- {
- $this->caption_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Enclosure', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for <media:copyright>
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for `<media:text>` captions
*/
- function set_copyright_class($class = 'SimplePie_Copyright')
+ public function set_caption_class($class = 'SimplePie_Caption')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Copyright'))
- {
- $this->copyright_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Caption', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for <media:credit>
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for `<media:copyright>`
*/
- function set_credit_class($class = 'SimplePie_Credit')
+ public function set_copyright_class($class = 'SimplePie_Copyright')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Credit'))
- {
- $this->credit_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Copyright', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for <media:rating>
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for `<media:credit>`
*/
- function set_rating_class($class = 'SimplePie_Rating')
+ public function set_credit_class($class = 'SimplePie_Credit')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Rating'))
- {
- $this->rating_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Credit', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for <media:restriction>
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for `<media:rating>`
*/
- function set_restriction_class($class = 'SimplePie_Restriction')
+ public function set_rating_class($class = 'SimplePie_Rating')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Restriction'))
- {
- $this->restriction_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Rating', $class, true);
}
/**
- * Allows you to change which class SimplePie uses for content-type sniffing.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for `<media:restriction>`
*/
- function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
+ public function set_restriction_class($class = 'SimplePie_Restriction')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer'))
- {
- $this->content_type_sniffer_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Restriction', $class, true);
}
/**
- * Allows you to change which class SimplePie uses item sources.
- * Useful when you are overloading or extending SimplePie's default classes.
- *
- * @access public
- * @param string $class Name of custom class.
- * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
- * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * Set which class SimplePie uses for content-type sniffing
*/
- function set_source_class($class = 'SimplePie_Source')
+ public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
{
- if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source'))
- {
- $this->source_class = $class;
- return true;
- }
- return false;
+ return $this->registry->register('Content_Type_Sniffer', $class, true);
}
/**
- * Allows you to override the default user agent string.
+ * Set which class SimplePie uses item sources
+ */
+ public function set_source_class($class = 'SimplePie_Source')
+ {
+ return $this->registry->register('Source', $class, true);
+ }
+ /**#@-*/
+
+ /**
+ * Set the user agent string
*
- * @access public
* @param string $ua New user agent string.
*/
- function set_useragent($ua = SIMPLEPIE_USERAGENT)
+ public function set_useragent($ua = SIMPLEPIE_USERAGENT)
{
$this->useragent = (string) $ua;
}
@@ -1334,10 +1047,9 @@ class SimplePie
/**
* Set callback function to create cache filename with
*
- * @access public
* @param mixed $function Callback function
*/
- function set_cache_name_function($function = 'md5')
+ public function set_cache_name_function($function = 'md5')
{
if (is_callable($function))
{
@@ -1346,31 +1058,14 @@ class SimplePie
}
/**
- * Set javascript query string parameter
+ * Set options to make SP as fast as possible
*
- * @access public
- * @param mixed $get Javascript query string parameter
- */
- function set_javascript($get = 'js')
- {
- if ($get)
- {
- $this->javascript = (string) $get;
- }
- else
- {
- $this->javascript = false;
- }
- }
-
- /**
- * Set options to make SP as fast as possible. Forgoes a
- * substantial amount of data sanitization in favor of speed.
+ * Forgoes a substantial amount of data sanitization in favor of speed. This
+ * turns SimplePie into a dumb parser of feeds.
*
- * @access public
* @param bool $set Whether to set them or not
*/
- function set_stupidly_fast($set = false)
+ public function set_stupidly_fast($set = false)
{
if ($set)
{
@@ -1386,20 +1081,19 @@ class SimplePie
/**
* Set maximum number of feeds to check with autodiscovery
*
- * @access public
* @param int $max Maximum number of feeds to check
*/
- function set_max_checked_feeds($max = 10)
+ public function set_max_checked_feeds($max = 10)
{
$this->max_checked_feeds = (int) $max;
}
- function remove_div($enable = true)
+ public function remove_div($enable = true)
{
$this->sanitize->remove_div($enable);
}
- function strip_htmltags($tags = '', $encode = null)
+ public function strip_htmltags($tags = '', $encode = null)
{
if ($tags === '')
{
@@ -1412,12 +1106,12 @@ class SimplePie
}
}
- function encode_instead_of_strip($enable = true)
+ public function encode_instead_of_strip($enable = true)
{
$this->sanitize->encode_instead_of_strip($enable);
}
- function strip_attributes($attribs = '')
+ public function strip_attributes($attribs = '')
{
if ($attribs === '')
{
@@ -1426,12 +1120,34 @@ class SimplePie
$this->sanitize->strip_attributes($attribs);
}
- function set_output_encoding($encoding = 'UTF-8')
+ /**
+ * Set the output encoding
+ *
+ * Allows you to override SimplePie's output to match that of your webpage.
+ * This is useful for times when your webpages are not being served as
+ * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
+ * is similar to {@see set_input_encoding()}.
+ *
+ * It should be noted, however, that not all character encodings can support
+ * all characters. If your page is being served as ISO-8859-1 and you try
+ * to display a Japanese feed, you'll likely see garbled characters.
+ * Because of this, it is highly recommended to ensure that your webpages
+ * are served as UTF-8.
+ *
+ * The number of supported character encodings depends on whether your web
+ * host supports {@link http://php.net/mbstring mbstring},
+ * {@link http://php.net/iconv iconv}, or both. See
+ * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
+ * more information.
+ *
+ * @param string $encoding
+ */
+ public function set_output_encoding($encoding = 'UTF-8')
{
$this->sanitize->set_output_encoding($encoding);
}
- function strip_comments($strip = false)
+ public function strip_comments($strip = false)
{
$this->sanitize->strip_comments($strip);
}
@@ -1440,42 +1156,25 @@ class SimplePie
* Set element/attribute key/value pairs of HTML attributes
* containing URLs that need to be resolved relative to the feed
*
- * @access public
+ * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
+ * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
+ * |q|@cite
+ *
* @since 1.0
- * @param array $element_attribute Element/attribute key/value pairs
+ * @param array|null $element_attribute Element/attribute key/value pairs, null for default
*/
- function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
+ public function set_url_replacements($element_attribute = null)
{
$this->sanitize->set_url_replacements($element_attribute);
}
/**
- * Set the handler to enable the display of cached favicons.
- *
- * @access public
- * @param str $page Web-accessible path to the handler_favicon.php file.
- * @param str $qs The query string that the value should be passed to.
- */
- function set_favicon_handler($page = false, $qs = 'i')
- {
- if ($page !== false)
- {
- $this->favicon_handler = $page . '?' . $qs . '=';
- }
- else
- {
- $this->favicon_handler = '';
- }
- }
-
- /**
* Set the handler to enable the display of cached images.
*
- * @access public
* @param str $page Web-accessible path to the handler_image.php file.
* @param str $qs The query string that the value should be passed to.
*/
- function set_image_handler($page = false, $qs = 'i')
+ public function set_image_handler($page = false, $qs = 'i')
{
if ($page !== false)
{
@@ -1488,20 +1187,28 @@ class SimplePie
}
/**
- * Set the limit for items returned per-feed with multifeeds.
+ * Set the limit for items returned per-feed with multifeeds
*
- * @access public
* @param integer $limit The maximum number of items to return.
*/
- function set_item_limit($limit = 0)
+ public function set_item_limit($limit = 0)
{
$this->item_limit = (int) $limit;
}
- function init()
+ /**
+ * Initialize the feed object
+ *
+ * This is what makes everything happen. Period. This is where all of the
+ * configuration options get processed, feeds are fetched, cached, and
+ * parsed, and all of that other good stuff.
+ *
+ * @return boolean True if successful, false otherwise
+ */
+ public function init()
{
// Check absolute bare minimum requirements.
- if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.3.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre'))
+ if (!extension_loaded('xml') || !extension_loaded('pcre'))
{
return false;
}
@@ -1522,331 +1229,383 @@ class SimplePie
}
}
- if (isset($_GET[$this->javascript]))
+ if (method_exists($this->sanitize, 'set_registry'))
{
- SimplePie_Misc::output_javascript();
- exit;
+ $this->sanitize->set_registry($this->registry);
}
// Pass whatever was set with config options over to the sanitizer.
- $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->cache_class);
- $this->sanitize->pass_file_data($this->file_class, $this->timeout, $this->useragent, $this->force_fsockopen);
+ // Pass the classes in for legacy support; new classes should use the registry instead
+ $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
+ $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
- if ($this->feed_url !== null || $this->raw_data !== null)
+ if (!empty($this->multifeed_url))
{
- $this->data = array();
+ $i = 0;
+ $success = 0;
$this->multifeed_objects = array();
- $cache = false;
-
- if ($this->feed_url !== null)
+ $this->error = array();
+ foreach ($this->multifeed_url as $url)
{
- $parsed_feed_url = SimplePie_Misc::parse_url($this->feed_url);
- // Decide whether to enable caching
- if ($this->cache && $parsed_feed_url['scheme'] !== '')
- {
- $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc');
- }
- // If it's enabled and we don't want an XML dump, use the cache
- if ($cache && !$this->xml_dump)
- {
- // Load the Cache
- $this->data = $cache->load();
- if (!empty($this->data))
- {
- // If the cache is for an outdated build of SimplePie
- if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
- {
- $cache->unlink();
- $this->data = array();
- }
- // If we've hit a collision just rerun it with caching disabled
- elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
- {
- $cache = false;
- $this->data = array();
- }
- // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
- elseif (isset($this->data['feed_url']))
- {
- // If the autodiscovery cache is still valid use it.
- if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
- {
- // Do not need to do feed autodiscovery yet.
- if ($this->data['feed_url'] === $this->data['url'])
- {
- $cache->unlink();
- $this->data = array();
- }
- else
- {
- $this->set_feed_url($this->data['feed_url']);
- return $this->init();
- }
- }
- }
- // Check if the cache has been updated
- elseif ($cache->mtime() + $this->cache_duration < time())
- {
- // If we have last-modified and/or etag set
- if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
- {
- $headers = array();
- if (isset($this->data['headers']['last-modified']))
- {
- $headers['if-modified-since'] = $this->data['headers']['last-modified'];
- }
- if (isset($this->data['headers']['etag']))
- {
- $headers['if-none-match'] = '"' . $this->data['headers']['etag'] . '"';
- }
- $file = new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen);
- if ($file->success)
- {
- if ($file->status_code === 304)
- {
- $cache->touch();
- return true;
- }
- else
- {
- $headers = $file->headers;
- }
- }
- else
- {
- unset($file);
- }
- }
- }
- // If the cache is still valid, just return true
- else
- {
- return true;
- }
- }
- // If the cache is empty, delete it
- else
- {
- $cache->unlink();
- $this->data = array();
- }
- }
- // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
- if (!isset($file))
+ $this->multifeed_objects[$i] = clone $this;
+ $this->multifeed_objects[$i]->set_feed_url($url);
+ $single_success = $this->multifeed_objects[$i]->init();
+ $success |= $single_success;
+ if (!$single_success)
{
- if (is_a($this->file, 'SimplePie_File') && $this->file->url === $this->feed_url)
- {
- $file =& $this->file;
- }
- else
- {
- $file = new $this->file_class($this->feed_url, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen);
- }
- }
- // If the file connection has an error, set SimplePie::error to that and quit
- if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
- {
- $this->error = $file->error;
- if (!empty($this->data))
- {
- return true;
- }
- else
- {
- return false;
- }
+ $this->error[$i] = $this->multifeed_objects[$i]->error();
}
+ $i++;
+ }
+ return (bool) $success;
+ }
+ elseif ($this->feed_url === null && $this->raw_data === null)
+ {
+ return false;
+ }
- if (!$this->force_feed)
- {
- // Check if the supplied URL is a feed, if it isn't, look for it.
- $locate = new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class);
- if (!$locate->is_feed($file))
- {
- // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
- unset($file);
- if ($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds))
- {
- if ($cache)
- {
- $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
- if (!$cache->save($this))
- {
- trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
- }
- $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc');
- }
- $this->feed_url = $file->url;
- }
- else
- {
- $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed.";
- SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
- return false;
- }
- }
- $locate = null;
- }
+ $this->error = null;
+ $this->data = array();
+ $this->multifeed_objects = array();
+ $cache = false;
+
+ if ($this->feed_url !== null)
+ {
+ $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
- $headers = $file->headers;
- $data = $file->body;
- $sniffer = new $this->content_type_sniffer_class($file);
- $sniffed = $sniffer->get_type();
+ // Decide whether to enable caching
+ if ($this->cache && $parsed_feed_url['scheme'] !== '')
+ {
+ $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
}
- else
+
+ // Fetch the data via SimplePie_File into $this->raw_data
+ if (($fetched = $this->fetch_data($cache)) === true)
{
- $data = $this->raw_data;
+ return true;
+ }
+ elseif ($fetched === false) {
+ return false;
}
- // Set up array of possible encodings
- $encodings = array();
+ list($headers, $sniffed) = $fetched;
+ }
- // First check to see if input has been overridden.
- if ($this->input_encoding !== false)
+ // Set up array of possible encodings
+ $encodings = array();
+
+ // First check to see if input has been overridden.
+ if ($this->input_encoding !== false)
+ {
+ $encodings[] = $this->input_encoding;
+ }
+
+ $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
+ $text_types = array('text/xml', 'text/xml-external-parsed-entity');
+
+ // RFC 3023 (only applies to sniffed content)
+ if (isset($sniffed))
+ {
+ if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
+ {
+ if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+ {
+ $encodings[] = strtoupper($charset[1]);
+ }
+ $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
+ $encodings[] = 'UTF-8';
+ }
+ elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
+ {
+ if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+ {
+ $encodings[] = $charset[1];
+ }
+ $encodings[] = 'US-ASCII';
+ }
+ // Text MIME-type default
+ elseif (substr($sniffed, 0, 5) === 'text/')
{
- $encodings[] = $this->input_encoding;
+ $encodings[] = 'US-ASCII';
}
+ }
+
+ // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
+ $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
+ $encodings[] = 'UTF-8';
+ $encodings[] = 'ISO-8859-1';
- $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
- $text_types = array('text/xml', 'text/xml-external-parsed-entity');
+ // There's no point in trying an encoding twice
+ $encodings = array_unique($encodings);
- // RFC 3023 (only applies to sniffed content)
- if (isset($sniffed))
+ // Loop through each possible encoding, till we return something, or run out of possibilities
+ foreach ($encodings as $encoding)
+ {
+ // Change the encoding to UTF-8 (as we always use UTF-8 internally)
+ if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
{
- if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
+ // Create new parser
+ $parser = $this->registry->create('Parser');
+
+ // If it's parsed fine
+ if ($parser->parse($utf8_data, 'UTF-8'))
{
- if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+ $this->data = $parser->get_data();
+ if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
{
- $encodings[] = strtoupper($charset[1]);
+ $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
+ return false;
}
- $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
- $encodings[] = 'UTF-8';
- }
- elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
- {
- if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+
+ if (isset($headers))
{
- $encodings[] = $charset[1];
+ $this->data['headers'] = $headers;
}
- $encodings[] = 'US-ASCII';
- }
- // Text MIME-type default
- elseif (substr($sniffed, 0, 5) === 'text/')
- {
- $encodings[] = 'US-ASCII';
+ $this->data['build'] = SIMPLEPIE_BUILD;
+
+ // Cache the file if caching is enabled
+ if ($cache && !$cache->save($this))
+ {
+ trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
+ }
+ return true;
}
}
+ }
- // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
- $encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
- $encodings[] = 'UTF-8';
- $encodings[] = 'ISO-8859-1';
+ if (isset($parser))
+ {
+ // We have an error, just set SimplePie_Misc::error to it and quit
+ $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
+ }
+ else
+ {
+ $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.';
+ }
- // There's no point in trying an encoding twice
- $encodings = array_unique($encodings);
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
- // If we want the XML, just output that with the most likely encoding and quit
- if ($this->xml_dump)
- {
- header('Content-type: text/xml; charset=' . $encodings[0]);
- echo $data;
- exit;
- }
+ return false;
+ }
- // Loop through each possible encoding, till we return something, or run out of possibilities
- foreach ($encodings as $encoding)
+ /**
+ * Fetch the data via SimplePie_File
+ *
+ * If the data is already cached, attempt to fetch it from there instead
+ * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
+ * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
+ */
+ protected function fetch_data(&$cache)
+ {
+ // If it's enabled, use the cache
+ if ($cache)
+ {
+ // Load the Cache
+ $this->data = $cache->load();
+ if (!empty($this->data))
{
- // Change the encoding to UTF-8 (as we always use UTF-8 internally)
- if ($utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8'))
+ // If the cache is for an outdated build of SimplePie
+ if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
{
- // Create new parser
- $parser = new $this->parser_class();
+ $cache->unlink();
+ $this->data = array();
+ }
+ // If we've hit a collision just rerun it with caching disabled
+ elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
+ {
+ $cache = false;
+ $this->data = array();
+ }
+ // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
+ elseif (isset($this->data['feed_url']))
+ {
+ // If the autodiscovery cache is still valid use it.
+ if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
+ {
+ // Do not need to do feed autodiscovery yet.
+ if ($this->data['feed_url'] !== $this->data['url'])
+ {
+ $this->set_feed_url($this->data['feed_url']);
+ return $this->init();
+ }
- // If it's parsed fine
- if ($parser->parse($utf8_data, 'UTF-8'))
+ $cache->unlink();
+ $this->data = array();
+ }
+ }
+ // Check if the cache has been updated
+ elseif ($cache->mtime() + $this->cache_duration < time())
+ {
+ // If we have last-modified and/or etag set
+ if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
{
- $this->data = $parser->get_data();
- if ($this->get_type() & ~SIMPLEPIE_TYPE_NONE)
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ if (isset($this->data['headers']['last-modified']))
{
- if (isset($headers))
- {
- $this->data['headers'] = $headers;
- }
- $this->data['build'] = SIMPLEPIE_BUILD;
+ $headers['if-modified-since'] = $this->data['headers']['last-modified'];
+ }
+ if (isset($this->data['headers']['etag']))
+ {
+ $headers['if-none-match'] = $this->data['headers']['etag'];
+ }
- // Cache the file if caching is enabled
- if ($cache && !$cache->save($this))
+ $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
+
+ if ($file->success)
+ {
+ if ($file->status_code === 304)
{
- trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
+ $cache->touch();
+ return true;
}
- return true;
}
else
{
- $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
- SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
- return false;
+ unset($file);
}
}
}
+ // If the cache is still valid, just return true
+ else
+ {
+ $this->raw_data = false;
+ return true;
+ }
}
- if (isset($parser))
+ // If the cache is empty, delete it
+ else
{
- // We have an error, just set SimplePie_Misc::error to it and quit
- $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
+ $cache->unlink();
+ $this->data = array();
+ }
+ }
+ // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
+ if (!isset($file))
+ {
+ if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
+ {
+ $file =& $this->file;
}
else
{
- $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.';
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
}
- SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
- return false;
}
- elseif (!empty($this->multifeed_url))
+ // If the file connection has an error, set SimplePie::error to that and quit
+ if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
{
- $i = 0;
- $success = 0;
- $this->multifeed_objects = array();
- foreach ($this->multifeed_url as $url)
+ $this->error = $file->error;
+ return !empty($this->data);
+ }
+
+ if (!$this->force_feed)
+ {
+ // Check if the supplied URL is a feed, if it isn't, look for it.
+ $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
+
+ if (!$locate->is_feed($file))
{
- if (SIMPLEPIE_PHP5)
+ // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
+ unset($file);
+ try
{
- // This keyword needs to defy coding standards for PHP4 compatibility
- $this->multifeed_objects[$i] = clone($this);
+ if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
+ {
+ $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed.";
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
+ return false;
+ }
}
- else
+ catch (SimplePie_Exception $e)
{
- $this->multifeed_objects[$i] = $this;
+ // This is usually because DOMDocument doesn't exist
+ $this->error = $e->getMessage();
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
+ return false;
}
- $this->multifeed_objects[$i]->set_feed_url($url);
- $success |= $this->multifeed_objects[$i]->init();
- $i++;
+ if ($cache)
+ {
+ $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
+ if (!$cache->save($this))
+ {
+ trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
+ }
+ $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
+ }
+ $this->feed_url = $file->url;
}
- return (bool) $success;
- }
- else
- {
- return false;
+ $locate = null;
}
+
+ $this->raw_data = $file->body;
+
+ $headers = $file->headers;
+ $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
+ $sniffed = $sniffer->get_type();
+
+ return array($headers, $sniffed);
}
/**
- * Return the error message for the occured error
+ * Get the error message for the occured error
*
- * @access public
- * @return string Error message
+ * @return string|array Error message, or array of messages for multifeeds
*/
- function error()
+ public function error()
{
return $this->error;
}
- function get_encoding()
+ /**
+ * Get the raw XML
+ *
+ * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
+ * the data instead of printing it.
+ *
+ * @return string|boolean Raw XML data, false if the cache is used
+ */
+ public function get_raw_data()
+ {
+ return $this->raw_data;
+ }
+
+ /**
+ * Get the character encoding used for output
+ *
+ * @since Preview Release
+ * @return string
+ */
+ public function get_encoding()
{
return $this->sanitize->output_encoding;
}
- function handle_content_type($mime = 'text/html')
+ /**
+ * Send the content-type header with correct encoding
+ *
+ * This method ensures that the SimplePie-enabled page is being served with
+ * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
+ * and character encoding HTTP headers (character encoding determined by the
+ * {@see set_output_encoding} config option).
+ *
+ * This won't work properly if any content or whitespace has already been
+ * sent to the browser, because it relies on PHP's
+ * {@link http://php.net/header header()} function, and these are the
+ * circumstances under which the function works.
+ *
+ * Because it's setting these settings for the entire page (as is the nature
+ * of HTTP headers), this should only be used once per page (again, at the
+ * top).
+ *
+ * @param string $mime MIME type to serve the page as
+ */
+ public function handle_content_type($mime = 'text/html')
{
if (!headers_sent())
{
@@ -1863,7 +1622,33 @@ class SimplePie
}
}
- function get_type()
+ /**
+ * Get the type of the feed
+ *
+ * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
+ * using {@link http://php.net/language.operators.bitwise bitwise operators}
+ *
+ * @since 0.8 (usage changed to using constants in 1.0)
+ * @see SIMPLEPIE_TYPE_NONE Unknown.
+ * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
+ * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
+ * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
+ * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
+ * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
+ * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
+ * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
+ * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
+ * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
+ * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
+ * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
+ * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
+ * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
+ * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
+ * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
+ * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
+ * @return int SIMPLEPIE_TYPE_* constant
+ */
+ public function get_type()
{
if (!isset($this->data['type']))
{
@@ -1944,72 +1729,18 @@ class SimplePie
}
/**
- * Returns the URL for the favicon of the feed's website.
+ * Get the URL for the feed
*
- * @todo Cache atom:icon
- * @access public
- * @since 1.0
- */
- function get_favicon()
- {
- if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
- }
- elseif (($url = $this->get_link()) !== null && preg_match('/^http(s)?:\/\//i', $url))
- {
- $favicon = SimplePie_Misc::absolutize_url('/favicon.ico', $url);
-
- if ($this->cache && $this->favicon_handler)
- {
- $favicon_filename = call_user_func($this->cache_name_function, $favicon);
- $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $favicon_filename, 'spi');
-
- if ($cache->load())
- {
- return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
- }
- else
- {
- $file = new $this->file_class($favicon, $this->timeout / 10, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
-
- if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)) && strlen($file->body) > 0)
- {
- $sniffer = new $this->content_type_sniffer_class($file);
- if (substr($sniffer->get_type(), 0, 6) === 'image/')
- {
- if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
- {
- return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
- }
- else
- {
- trigger_error("$cache->name is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
- return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
- }
- }
- // not an image
- else
- {
- return false;
- }
- }
- }
- }
- else
- {
- return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
- }
- }
- return false;
- }
-
- /**
+ * May or may not be different from the URL passed to {@see set_feed_url()},
+ * depending on whether auto-discovery was used.
+ *
+ * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
* @todo If we have a perm redirect we should return the new URL
* @todo When we make the above change, let's support <itunes:new-feed-url> as well
* @todo Also, |atom:link|@rel=self
+ * @return string|null
*/
- function subscribe_url()
+ public function subscribe_url()
{
if ($this->feed_url !== null)
{
@@ -2021,156 +1752,38 @@ class SimplePie
}
}
- function subscribe_feed()
- {
- if ($this->feed_url !== null)
- {
- return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
- }
- else
- {
- return null;
- }
- }
-
- function subscribe_outlook()
- {
- if ($this->feed_url !== null)
- {
- return $this->sanitize('outlook' . SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
- }
- else
- {
- return null;
- }
- }
-
- function subscribe_podcast()
- {
- if ($this->feed_url !== null)
- {
- return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 3), SIMPLEPIE_CONSTRUCT_IRI);
- }
- else
- {
- return null;
- }
- }
-
- function subscribe_itunes()
- {
- if ($this->feed_url !== null)
- {
- return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 4), SIMPLEPIE_CONSTRUCT_IRI);
- }
- else
- {
- return null;
- }
- }
-
/**
- * Creates the subscribe_* methods' return data
+ * Get data for an feed-level element
*
- * @access private
- * @param string $feed_url String to prefix to the feed URL
- * @param string $site_url String to prefix to the site URL (and
- * suffix to the feed URL)
- * @return mixed URL if feed exists, false otherwise
+ * This method allows you to get access to ANY element/attribute that is a
+ * sub-element of the opening feed tag.
+ *
+ * The return value is an indexed array of elements matching the given
+ * namespace and tag name. Each element has `attribs`, `data` and `child`
+ * subkeys. For `attribs` and `child`, these contain namespace subkeys.
+ * `attribs` then has one level of associative name => value data (where
+ * `value` is a string) after the namespace. `child` has tag-indexed keys
+ * after the namespace, each member of which is an indexed array matching
+ * this same format.
+ *
+ * For example:
+ * <pre>
+ * // This is probably a bad example because we already support
+ * // <media:content> natively, but it shows you how to parse through
+ * // the nodes.
+ * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
+ * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
+ * $file = $content[0]['attribs']['']['url'];
+ * echo $file;
+ * </pre>
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
*/
- function subscribe_service($feed_url, $site_url = null)
- {
- if ($this->subscribe_url())
- {
- $return = $feed_url . rawurlencode($this->feed_url);
- if ($site_url !== null && $this->get_link() !== null)
- {
- $return .= $site_url . rawurlencode($this->get_link());
- }
- return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI);
- }
- else
- {
- return null;
- }
- }
-
- function subscribe_aol()
- {
- return $this->subscribe_service('http://feeds.my.aol.com/add.jsp?url=');
- }
-
- function subscribe_bloglines()
- {
- return $this->subscribe_service('http://www.bloglines.com/sub/');
- }
-
- function subscribe_eskobo()
- {
- return $this->subscribe_service('http://www.eskobo.com/?AddToMyPage=');
- }
-
- function subscribe_feedfeeds()
- {
- return $this->subscribe_service('http://www.feedfeeds.com/add?feed=');
- }
-
- function subscribe_feedster()
- {
- return $this->subscribe_service('http://www.feedster.com/myfeedster.php?action=addrss&confirm=no&rssurl=');
- }
-
- function subscribe_google()
- {
- return $this->subscribe_service('http://fusion.google.com/add?feedurl=');
- }
-
- function subscribe_gritwire()
- {
- return $this->subscribe_service('http://my.gritwire.com/feeds/addExternalFeed.aspx?FeedUrl=');
- }
-
- function subscribe_msn()
- {
- return $this->subscribe_service('http://my.msn.com/addtomymsn.armx?id=rss&ut=', '&ru=');
- }
-
- function subscribe_netvibes()
- {
- return $this->subscribe_service('http://www.netvibes.com/subscribe.php?url=');
- }
-
- function subscribe_newsburst()
- {
- return $this->subscribe_service('http://www.newsburst.com/Source/?add=');
- }
-
- function subscribe_newsgator()
- {
- return $this->subscribe_service('http://www.newsgator.com/ngs/subscriber/subext.aspx?url=');
- }
-
- function subscribe_odeo()
- {
- return $this->subscribe_service('http://www.odeo.com/listen/subscribe?feed=');
- }
-
- function subscribe_podnova()
- {
- return $this->subscribe_service('http://www.podnova.com/index_your_podcasts.srf?action=add&url=');
- }
-
- function subscribe_rojo()
- {
- return $this->subscribe_service('http://www.rojo.com/add-subscription?resource=');
- }
-
- function subscribe_yahoo()
- {
- return $this->subscribe_service('http://add.my.yahoo.com/rss?url=');
- }
-
- function get_feed_tags($namespace, $tag)
+ public function get_feed_tags($namespace, $tag)
{
$type = $this->get_type();
if ($type & SIMPLEPIE_TYPE_ATOM_10)
@@ -2204,7 +1817,21 @@ class SimplePie
return null;
}
- function get_channel_tags($namespace, $tag)
+ /**
+ * Get data for an channel-level element
+ *
+ * This method allows you to get access to ANY element/attribute in the
+ * channel/header section of the feed.
+ *
+ * See {@see SimplePie::get_feed_tags()} for a description of the return value
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
+ */
+ public function get_channel_tags($namespace, $tag)
{
$type = $this->get_type();
if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
@@ -2247,7 +1874,21 @@ class SimplePie
return null;
}
- function get_image_tags($namespace, $tag)
+ /**
+ * Get data for an channel-level element
+ *
+ * This method allows you to get access to ANY element/attribute in the
+ * image/logo section of the feed.
+ *
+ * See {@see SimplePie::get_feed_tags()} for a description of the return value
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
+ */
+ public function get_image_tags($namespace, $tag)
{
$type = $this->get_type();
if ($type & SIMPLEPIE_TYPE_RSS_10)
@@ -2283,7 +1924,19 @@ class SimplePie
return null;
}
- function get_base($element = array())
+ /**
+ * Get the base URL value from the feed
+ *
+ * Uses `<xml:base>` if available, otherwise uses the first link in the
+ * feed, or failing that, the URL of the feed itself.
+ *
+ * @see get_link
+ * @see subscribe_url
+ *
+ * @param array $element
+ * @return string
+ */
+ public function get_base($element = array())
{
if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
{
@@ -2299,20 +1952,38 @@ class SimplePie
}
}
- function sanitize($data, $type, $base = '')
+ /**
+ * Sanitize feed data
+ *
+ * @access private
+ * @see SimplePie_Sanitize::sanitize()
+ * @param string $data Data to sanitize
+ * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
+ * @param string $base Base URL to resolve URLs against
+ * @return string Sanitized data
+ */
+ public function sanitize($data, $type, $base = '')
{
return $this->sanitize->sanitize($data, $type, $base);
}
- function get_title()
+ /**
+ * Get the title of the feed
+ *
+ * Uses `<atom:title>`, `<title>` or `<dc:title>`
+ *
+ * @since 1.0 (previously called `get_feed_title` since 0.8)
+ * @return string|null
+ */
+ public function get_title()
{
if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
{
@@ -2340,7 +2011,14 @@ class SimplePie
}
}
- function get_category($key = 0)
+ /**
+ * Get a category for the feed
+ *
+ * @since Unknown
+ * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Category|null
+ */
+ public function get_category($key = 0)
{
$categories = $this->get_categories();
if (isset($categories[$key]))
@@ -2353,7 +2031,15 @@ class SimplePie
}
}
- function get_categories()
+ /**
+ * Get all categories for the feed
+ *
+ * Uses `<atom:category>`, `<category>` or `<dc:subject>`
+ *
+ * @since Unknown
+ * @return array|null List of {@see SimplePie_Category} objects
+ */
+ public function get_categories()
{
$categories = array();
@@ -2374,7 +2060,7 @@ class SimplePie
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories[] = new $this->category_class($term, $scheme, $label);
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
}
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
{
@@ -2389,20 +2075,20 @@ class SimplePie
{
$scheme = null;
}
- $categories[] = new $this->category_class($term, $scheme, null);
+ $categories[] = $this->registry->create('Category', array($term, $scheme, null));
}
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
{
- $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
{
- $categories[] = new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
if (!empty($categories))
{
- return SimplePie_Misc::array_unique($categories);
+ return array_unique($categories);
}
else
{
@@ -2410,7 +2096,14 @@ class SimplePie
}
}
- function get_author($key = 0)
+ /**
+ * Get an author for the feed
+ *
+ * @since 1.1
+ * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_author($key = 0)
{
$authors = $this->get_authors();
if (isset($authors[$key]))
@@ -2423,7 +2116,15 @@ class SimplePie
}
}
- function get_authors()
+ /**
+ * Get all authors for the feed
+ *
+ * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
+ *
+ * @since 1.1
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_authors()
{
$authors = array();
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
@@ -2445,7 +2146,7 @@ class SimplePie
}
if ($name !== null || $email !== null || $uri !== null)
{
- $authors[] = new $this->author_class($name, $uri, $email);
+ $authors[] = $this->registry->create('Author', array($name, $uri, $email));
}
}
if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
@@ -2467,25 +2168,25 @@ class SimplePie
}
if ($name !== null || $email !== null || $url !== null)
{
- $authors[] = new $this->author_class($name, $url, $email);
+ $authors[] = $this->registry->create('Author', array($name, $url, $email));
}
}
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
{
- $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
{
- $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
{
- $authors[] = new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
if (!empty($authors))
{
- return SimplePie_Misc::array_unique($authors);
+ return array_unique($authors);
}
else
{
@@ -2493,7 +2194,14 @@ class SimplePie
}
}
- function get_contributor($key = 0)
+ /**
+ * Get a contributor for the feed
+ *
+ * @since 1.1
+ * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_contributor($key = 0)
{
$contributors = $this->get_contributors();
if (isset($contributors[$key]))
@@ -2506,7 +2214,15 @@ class SimplePie
}
}
- function get_contributors()
+ /**
+ * Get all contributors for the feed
+ *
+ * Uses `<atom:contributor>`
+ *
+ * @since 1.1
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_contributors()
{
$contributors = array();
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
@@ -2528,7 +2244,7 @@ class SimplePie
}
if ($name !== null || $email !== null || $uri !== null)
{
- $contributors[] = new $this->author_class($name, $uri, $email);
+ $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
}
}
foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
@@ -2550,13 +2266,13 @@ class SimplePie
}
if ($name !== null || $email !== null || $url !== null)
{
- $contributors[] = new $this->author_class($name, $url, $email);
+ $contributors[] = $this->registry->create('Author', array($name, $url, $email));
}
}
if (!empty($contributors))
{
- return SimplePie_Misc::array_unique($contributors);
+ return array_unique($contributors);
}
else
{
@@ -2564,7 +2280,15 @@ class SimplePie
}
}
- function get_link($key = 0, $rel = 'alternate')
+ /**
+ * Get a single link for the feed
+ *
+ * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
+ * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
+ * @param string $rel The relationship of the link to return
+ * @return string|null Link URL
+ */
+ public function get_link($key = 0, $rel = 'alternate')
{
$links = $this->get_links($rel);
if (isset($links[$key]))
@@ -2578,14 +2302,31 @@ class SimplePie
}
/**
- * Added for parity between the parent-level and the item/entry-level.
+ * Get the permalink for the item
+ *
+ * Returns the first link available with a relationship of "alternate".
+ * Identical to {@see get_link()} with key 0
+ *
+ * @see get_link
+ * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
+ * @internal Added for parity between the parent-level and the item/entry-level.
+ * @return string|null Link URL
*/
- function get_permalink()
+ public function get_permalink()
{
return $this->get_link(0);
}
- function get_links($rel = 'alternate')
+ /**
+ * Get all links for the feed
+ *
+ * Uses `<atom:link>` or `<link>`
+ *
+ * @since Beta 2
+ * @param string $rel The relationship of links to return
+ * @return array|null Links found for the feed (strings)
+ */
+ public function get_links($rel = 'alternate')
{
if (!isset($this->data['links']))
{
@@ -2629,7 +2370,7 @@ class SimplePie
$keys = array_keys($this->data['links']);
foreach ($keys as $key)
{
- if (SimplePie_Misc::is_isegment_nz_nc($key))
+ if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
{
if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
{
@@ -2659,20 +2400,29 @@ class SimplePie
}
}
- function get_all_discovered_feeds()
+ public function get_all_discovered_feeds()
{
return $this->all_discovered_feeds;
}
- function get_description()
+ /**
+ * Get the content for the item
+ *
+ * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
+ * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
+ *
+ * @since 1.0 (previously called `get_feed_description()` since 0.8)
+ * @return string|null
+ */
+ public function get_description()
{
if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
{
@@ -2708,15 +2458,23 @@ class SimplePie
}
}
- function get_copyright()
+ /**
+ * Get the copyright info for the feed
+ *
+ * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
+ *
+ * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
+ * @return string|null
+ */
+ public function get_copyright()
{
if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
{
@@ -2736,7 +2494,15 @@ class SimplePie
}
}
- function get_language()
+ /**
+ * Get the language for the feed
+ *
+ * Uses `<language>`, `<dc:language>`, or @xml_lang
+ *
+ * @since 1.0 (previously called `get_feed_language()` since 0.8)
+ * @return string|null
+ */
+ public function get_language()
{
if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
{
@@ -2772,9 +2538,21 @@ class SimplePie
}
}
- function get_latitude()
+ /**
+ * Get the latitude coordinates for the item
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:lat>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_latitude()
{
-
+
if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
{
return (float) $return[0]['data'];
@@ -2789,7 +2567,19 @@ class SimplePie
}
}
- function get_longitude()
+ /**
+ * Get the longitude coordinates for the feed
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_longitude()
{
if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
{
@@ -2809,7 +2599,16 @@ class SimplePie
}
}
- function get_image_title()
+ /**
+ * Get the feed logo's title
+ *
+ * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
+ *
+ * Uses `<image><title>` or `<image><dc:title>`
+ *
+ * @return string|null
+ */
+ public function get_image_title()
{
if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
{
@@ -2837,7 +2636,18 @@ class SimplePie
}
}
- function get_image_url()
+ /**
+ * Get the feed logo's URL
+ *
+ * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
+ * have a "feed logo" URL. This points directly to the image itself.
+ *
+ * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
+ * `<image><title>` or `<image><dc:title>`
+ *
+ * @return string|null
+ */
+ public function get_image_url()
{
if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
{
@@ -2869,7 +2679,18 @@ class SimplePie
}
}
- function get_image_link()
+ /**
+ * Get the feed logo's link
+ *
+ * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
+ * points to a human-readable page that the image should link to.
+ *
+ * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
+ * `<image><title>` or `<image><dc:title>`
+ *
+ * @return string|null
+ */
+ public function get_image_link()
{
if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
{
@@ -2889,7 +2710,17 @@ class SimplePie
}
}
- function get_image_width()
+ /**
+ * Get the feed logo's link
+ *
+ * RSS 2.0 feeds are allowed to have a "feed logo" width.
+ *
+ * Uses `<image><width>` or defaults to 88.0 if no width is specified and
+ * the feed is an RSS 2.0 feed.
+ *
+ * @return int|float|null
+ */
+ public function get_image_width()
{
if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
{
@@ -2905,7 +2736,17 @@ class SimplePie
}
}
- function get_image_height()
+ /**
+ * Get the feed logo's height
+ *
+ * RSS 2.0 feeds are allowed to have a "feed logo" height.
+ *
+ * Uses `<image><height>` or defaults to 31.0 if no height is specified and
+ * the feed is an RSS 2.0 feed.
+ *
+ * @return int|float|null
+ */
+ public function get_image_height()
{
if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
{
@@ -2921,7 +2762,16 @@ class SimplePie
}
}
- function get_item_quantity($max = 0)
+ /**
+ * Get the number of items in the feed
+ *
+ * This is well-suited for {@link http://php.net/for for()} loops with
+ * {@see get_item()}
+ *
+ * @param int $max Maximum value to return. 0 for no limit
+ * @return int Number of items in the feed
+ */
+ public function get_item_quantity($max = 0)
{
$max = (int) $max;
$qty = count($this->get_items());
@@ -2935,7 +2785,19 @@ class SimplePie
}
}
- function get_item($key = 0)
+ /**
+ * Get a single item from the feed
+ *
+ * This is better suited for {@link http://php.net/for for()} loops, whereas
+ * {@see get_items()} is better suited for
+ * {@link http://php.net/foreach foreach()} loops.
+ *
+ * @see get_item_quantity()
+ * @since Beta 2
+ * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Item|null
+ */
+ public function get_item($key = 0)
{
$items = $this->get_items();
if (isset($items[$key]))
@@ -2948,7 +2810,20 @@ class SimplePie
}
}
- function get_items($start = 0, $end = 0)
+ /**
+ * Get all items from the feed
+ *
+ * This is better suited for {@link http://php.net/for for()} loops, whereas
+ * {@see get_items()} is better suited for
+ * {@link http://php.net/foreach foreach()} loops.
+ *
+ * @see get_item_quantity
+ * @since Beta 2
+ * @param int $start Index to start at
+ * @param int $end Number of items to return. 0 for all items after `$start`
+ * @return array|null List of {@see SimplePie_Item} objects
+ */
+ public function get_items($start = 0, $end = 0)
{
if (!isset($this->data['items']))
{
@@ -2964,7 +2839,7 @@ class SimplePie
$keys = array_keys($items);
foreach ($keys as $key)
{
- $this->data['items'][] = new $this->item_class($this, $items[$key]);
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
}
}
if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
@@ -2972,7 +2847,7 @@ class SimplePie
$keys = array_keys($items);
foreach ($keys as $key)
{
- $this->data['items'][] = new $this->item_class($this, $items[$key]);
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
}
}
if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
@@ -2980,7 +2855,7 @@ class SimplePie
$keys = array_keys($items);
foreach ($keys as $key)
{
- $this->data['items'][] = new $this->item_class($this, $items[$key]);
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
}
}
if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
@@ -2988,7 +2863,7 @@ class SimplePie
$keys = array_keys($items);
foreach ($keys as $key)
{
- $this->data['items'][] = new $this->item_class($this, $items[$key]);
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
}
}
if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
@@ -2996,7 +2871,7 @@ class SimplePie
$keys = array_keys($items);
foreach ($keys as $key)
{
- $this->data['items'][] = new $this->item_class($this, $items[$key]);
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
}
}
}
@@ -3022,7 +2897,7 @@ class SimplePie
$this->data['ordered_items'] = $this->data['items'];
if ($do_sort)
{
- usort($this->data['ordered_items'], array(&$this, 'sort_items'));
+ usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
}
}
$items = $this->data['ordered_items'];
@@ -3049,24 +2924,98 @@ class SimplePie
}
/**
- * @static
+ * Set the favicon handler
+ *
+ * @deprecated Use your own favicon handling instead
+ */
+ public function set_favicon_handler($page = false, $qs = 'i')
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('Favicon handling has been removed, please use your own handling', $level);
+ return false;
+ }
+
+ /**
+ * Get the favicon for the current feed
+ *
+ * @deprecated Use your own favicon handling instead
+ */
+ public function get_favicon()
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('Favicon handling has been removed, please use your own handling', $level);
+
+ if (($url = $this->get_link()) !== null)
+ {
+ return 'http://g.etfv.co/' . urlencode($url);
+ }
+
+ return false;
+ }
+
+ /**
+ * Magic method handler
+ *
+ * @param string $method Method name
+ * @param array $args Arguments to the method
+ * @return mixed
*/
- function sort_items($a, $b)
+ public function __call($method, $args)
+ {
+ if (strpos($method, 'subscribe_') === 0)
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
+ return '';
+ }
+ if ($method === 'enable_xml_dump')
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
+ return false;
+ }
+
+ $class = get_class($this);
+ $trace = debug_backtrace();
+ $file = $trace[0]['file'];
+ $line = $trace[0]['line'];
+ trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
+ }
+
+ /**
+ * Sorting callback for items
+ *
+ * @access private
+ * @param SimplePie $a
+ * @param SimplePie $b
+ * @return boolean
+ */
+ public static function sort_items($a, $b)
{
return $a->get_date('U') <= $b->get_date('U');
}
/**
- * @static
+ * Merge items from several feeds into one
+ *
+ * If you're merging multiple feeds together, they need to all have dates
+ * for the items or else SimplePie will refuse to sort them.
+ *
+ * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
+ * @param array $urls List of SimplePie feed objects to merge
+ * @param int $start Starting item
+ * @param int $end Number of items to return
+ * @param int $limit Maximum number of items per feed
+ * @return array
*/
- function merge_items($urls, $start = 0, $end = 0, $limit = 0)
+ public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
{
if (is_array($urls) && sizeof($urls) > 0)
{
$items = array();
foreach ($urls as $arg)
{
- if (is_a($arg, 'SimplePie'))
+ if ($arg instanceof SimplePie)
{
$items = array_merge($items, $arg->get_items(0, $limit));
}
@@ -3088,7 +3037,7 @@ class SimplePie
$item = null;
if ($do_sort)
{
- usort($items, array('SimplePie', 'sort_items'));
+ usort($items, array(get_class($urls[0]), 'sort_items'));
}
if ($end === 0)
@@ -3108,18 +3057,6030 @@ class SimplePie
}
}
+/**
+ * Manages all author-related data
+ *
+ * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_author_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Author
+{
+ /**
+ * Author's name
+ *
+ * @var string
+ * @see get_name()
+ */
+ var $name;
+
+ /**
+ * Author's link
+ *
+ * @var string
+ * @see get_link()
+ */
+ var $link;
+
+ /**
+ * Author's email address
+ *
+ * @var string
+ * @see get_email()
+ */
+ var $email;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * @param string $name
+ * @param string $link
+ * @param string $email
+ */
+ public function __construct($name = null, $link = null, $email = null)
+ {
+ $this->name = $name;
+ $this->link = $link;
+ $this->email = $email;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Author's name
+ *
+ * @return string|null
+ */
+ public function get_name()
+ {
+ if ($this->name !== null)
+ {
+ return $this->name;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Author's link
+ *
+ * @return string|null
+ */
+ public function get_link()
+ {
+ if ($this->link !== null)
+ {
+ return $this->link;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Author's email address
+ *
+ * @return string|null
+ */
+ public function get_email()
+ {
+ if ($this->email !== null)
+ {
+ return $this->email;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * Base for cache objects
+ *
+ * Classes to be used with {@see SimplePie_Cache::register()} are expected
+ * to implement this interface.
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+interface SimplePie_Cache_Base
+{
+ /**
+ * Feed cache type
+ *
+ * @var string
+ */
+ const TYPE_FEED = 'spc';
+
+ /**
+ * Image cache type
+ *
+ * @var string
+ */
+ const TYPE_IMAGE = 'spi';
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type);
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data);
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load();
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime();
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch();
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink();
+}
+
+/**
+ * Base class for database-based caches
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
+{
+ /**
+ * Helper for database conversion
+ *
+ * Converts a given {@see SimplePie} object into data to be stored
+ *
+ * @param SimplePie $data
+ * @return array First item is the serialized data for storage, second item is the unique ID for this item
+ */
+ protected static function prepare_simplepie_object_for_cache($data)
+ {
+ $items = $data->get_items();
+ $items_by_id = array();
+
+ if (!empty($items))
+ {
+ foreach ($items as $item)
+ {
+ $items_by_id[$item->get_id()] = $item;
+ }
+
+ if (count($items_by_id) !== count($items))
+ {
+ $items_by_id = array();
+ foreach ($items as $item)
+ {
+ $items_by_id[$item->get_id(true)] = $item;
+ }
+ }
+
+ if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
+ }
+ elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
+ }
+ elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
+ }
+ elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
+ }
+ else
+ {
+ $channel = null;
+ }
+
+ if ($channel !== null)
+ {
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
+ }
+ }
+ if (isset($data->data['items']))
+ {
+ unset($data->data['items']);
+ }
+ if (isset($data->data['ordered_items']))
+ {
+ unset($data->data['ordered_items']);
+ }
+ }
+ return array(serialize($data->data), $items_by_id);
+ }
+}
+
+/**
+ * Caches data to the filesystem
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+class SimplePie_Cache_File implements SimplePie_Cache_Base
+{
+ /**
+ * Location string
+ *
+ * @see SimplePie::$cache_location
+ * @var string
+ */
+ protected $location;
+
+ /**
+ * Filename
+ *
+ * @var string
+ */
+ protected $filename;
+
+ /**
+ * File extension
+ *
+ * @var string
+ */
+ protected $extension;
+
+ /**
+ * File path
+ *
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type)
+ {
+ $this->location = $location;
+ $this->filename = $name;
+ $this->extension = $type;
+ $this->name = "$this->location/$this->filename.$this->extension";
+ }
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data)
+ {
+ if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
+ {
+ if ($data instanceof SimplePie)
+ {
+ $data = $data->data;
+ }
+
+ $data = serialize($data);
+ return (bool) file_put_contents($this->name, $data);
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load()
+ {
+ if (file_exists($this->name) && is_readable($this->name))
+ {
+ return unserialize(file_get_contents($this->name));
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime()
+ {
+ if (file_exists($this->name))
+ {
+ return filemtime($this->name);
+ }
+ return false;
+ }
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch()
+ {
+ if (file_exists($this->name))
+ {
+ return touch($this->name);
+ }
+ return false;
+ }
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink()
+ {
+ if (file_exists($this->name))
+ {
+ return unlink($this->name);
+ }
+ return false;
+ }
+}
+
+/**
+ * Caches data to memcache
+ *
+ * Registered for URLs with the "memcache" protocol
+ *
+ * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
+ * connect to memcache on `localhost` on port 11211. All tables will be
+ * prefixed with `sp_` and data will expire after 3600 seconds
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ * @uses Memcache
+ */
+class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
+{
+ /**
+ * Memcache instance
+ *
+ * @var Memcache
+ */
+ protected $cache;
+
+ /**
+ * Options
+ *
+ * @var array
+ */
+ protected $options;
+
+ /**
+ * Cache name
+ *
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type)
+ {
+ $this->options = array(
+ 'host' => '127.0.0.1',
+ 'port' => 11211,
+ 'extras' => array(
+ 'timeout' => 3600, // one hour
+ 'prefix' => 'simplepie_',
+ ),
+ );
+ $parsed = SimplePie_Cache::parse_URL($location);
+ $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
+ $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
+ $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
+ $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
+
+ $this->cache = new Memcache();
+ $this->cache->addServer($this->options['host'], (int) $this->options['port']);
+ }
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data)
+ {
+ if ($data instanceof SimplePie)
+ {
+ $data = $data->data;
+ }
+ return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
+ }
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load()
+ {
+ $data = $this->cache->get($this->name);
+
+ if ($data !== false)
+ {
+ return unserialize($data);
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime()
+ {
+ $data = $this->cache->get($this->name);
+
+ if ($data !== false)
+ {
+ // essentially ignore the mtime because Memcache expires on it's own
+ return time();
+ }
+
+ return false;
+ }
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch()
+ {
+ $data = $this->cache->get($this->name);
+
+ if ($data !== false)
+ {
+ return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink()
+ {
+ return $this->cache->delete($this->name, 0);
+ }
+}
+
+/**
+ * Caches data to a MySQL database
+ *
+ * Registered for URLs with the "mysql" protocol
+ *
+ * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
+ * connect to the `mydb` database on `localhost` on port 3306, with the user
+ * `root` and the password `password`. All tables will be prefixed with `sp_`
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
+{
+ /**
+ * PDO instance
+ *
+ * @var PDO
+ */
+ protected $mysql;
+
+ /**
+ * Options
+ *
+ * @var array
+ */
+ protected $options;
+
+ /**
+ * Cache ID
+ *
+ * @var string
+ */
+ protected $id;
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type)
+ {
+ $this->options = array(
+ 'user' => null,
+ 'pass' => null,
+ 'host' => '127.0.0.1',
+ 'port' => '3306',
+ 'path' => '',
+ 'extras' => array(
+ 'prefix' => '',
+ ),
+ );
+ $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
+
+ // Path is prefixed with a "/"
+ $this->options['dbname'] = substr($this->options['path'], 1);
+
+ try
+ {
+ $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
+ }
+ catch (PDOException $e)
+ {
+ $this->mysql = null;
+ return;
+ }
+
+ $this->id = $name . $type;
+
+ if (!$query = $this->mysql->query('SHOW TABLES'))
+ {
+ $this->mysql = null;
+ return;
+ }
+
+ $db = array();
+ while ($row = $query->fetchColumn())
+ {
+ $db[] = $row;
+ }
+
+ if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
+ {
+ $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
+ if ($query === false)
+ {
+ $this->mysql = null;
+ }
+ }
+
+ if (!in_array($this->options['extras']['prefix'] . 'items', $db))
+ {
+ $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
+ if ($query === false)
+ {
+ $this->mysql = null;
+ }
+ }
+ }
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data)
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ if ($data instanceof SimplePie)
+ {
+ $data = clone $data;
+
+ $prepared = self::prepare_simplepie_object_for_cache($data);
+
+ $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
+ $query->bindValue(':feed', $this->id);
+ if ($query->execute())
+ {
+ if ($query->fetchColumn() > 0)
+ {
+ $items = count($prepared[1]);
+ if ($items)
+ {
+ $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
+ $query = $this->mysql->prepare($sql);
+ $query->bindValue(':items', $items);
+ }
+ else
+ {
+ $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
+ $query = $this->mysql->prepare($sql);
+ }
+
+ $query->bindValue(':data', $prepared[0]);
+ $query->bindValue(':time', time());
+ $query->bindValue(':feed', $this->id);
+ if (!$query->execute())
+ {
+ return false;
+ }
+ }
+ else
+ {
+ $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
+ $query->bindValue(':feed', $this->id);
+ $query->bindValue(':count', count($prepared[1]));
+ $query->bindValue(':data', $prepared[0]);
+ $query->bindValue(':time', time());
+ if (!$query->execute())
+ {
+ return false;
+ }
+ }
+
+ $ids = array_keys($prepared[1]);
+ if (!empty($ids))
+ {
+ foreach ($ids as $id)
+ {
+ $database_ids[] = $this->mysql->quote($id);
+ }
+
+ $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
+ $query->bindValue(':feed', $this->id);
+
+ if ($query->execute())
+ {
+ $existing_ids = array();
+ while ($row = $query->fetchColumn())
+ {
+ $existing_ids[] = $row;
+ }
+
+ $new_ids = array_diff($ids, $existing_ids);
+
+ foreach ($new_ids as $new_id)
+ {
+ if (!($date = $prepared[1][$new_id]->get_date('U')))
+ {
+ $date = time();
+ }
+
+ $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
+ $query->bindValue(':feed', $this->id);
+ $query->bindValue(':id', $new_id);
+ $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
+ $query->bindValue(':date', $date);
+ if (!$query->execute())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
+ $query->bindValue(':feed', $this->id);
+ if ($query->execute())
+ {
+ if ($query->rowCount() > 0)
+ {
+ $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
+ $query->bindValue(':data', serialize($data));
+ $query->bindValue(':time', time());
+ $query->bindValue(':feed', $this->id);
+ if ($this->execute())
+ {
+ return true;
+ }
+ }
+ else
+ {
+ $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
+ $query->bindValue(':id', $this->id);
+ $query->bindValue(':data', serialize($data));
+ $query->bindValue(':time', time());
+ if ($query->execute())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
+ $query->bindValue(':id', $this->id);
+ if ($query->execute() && ($row = $query->fetch()))
+ {
+ $data = unserialize($row[1]);
+
+ if (isset($this->options['items'][0]))
+ {
+ $items = (int) $this->options['items'][0];
+ }
+ else
+ {
+ $items = (int) $row[0];
+ }
+
+ if ($items !== 0)
+ {
+ if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
+ }
+ elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
+ }
+ elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
+ }
+ elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
+ }
+ else
+ {
+ $feed = null;
+ }
+
+ if ($feed !== null)
+ {
+ $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
+ if ($items > 0)
+ {
+ $sql .= ' LIMIT ' . $items;
+ }
+
+ $query = $this->mysql->prepare($sql);
+ $query->bindValue(':feed', $this->id);
+ if ($query->execute())
+ {
+ while ($row = $query->fetchColumn())
+ {
+ $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ return $data;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
+ $query->bindValue(':id', $this->id);
+ if ($query->execute() && ($time = $query->fetchColumn()))
+ {
+ return $time;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
+ $query->bindValue(':time', time());
+ $query->bindValue(':id', $this->id);
+ if ($query->execute() && $query->rowCount() > 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
+ $query->bindValue(':id', $this->id);
+ $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
+ $query2->bindValue(':id', $this->id);
+ if ($query->execute() && $query2->execute())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+/**
+ * Used to create cache objects
+ *
+ * This class can be overloaded with {@see SimplePie::set_cache_class()},
+ * although the preferred way is to create your own handler
+ * via {@see register()}
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+class SimplePie_Cache
+{
+ /**
+ * Cache handler classes
+ *
+ * These receive 3 parameters to their constructor, as documented in
+ * {@see register()}
+ * @var array
+ */
+ protected static $handlers = array(
+ 'mysql' => 'SimplePie_Cache_MySQL',
+ 'memcache' => 'SimplePie_Cache_Memcache',
+ );
+
+ /**
+ * Don't call the constructor. Please.
+ */
+ private function __construct() { }
+
+ /**
+ * Create a new SimplePie_Cache object
+ *
+ * @param string $location URL location (scheme is used to determine handler)
+ * @param string $filename Unique identifier for cache object
+ * @param string $extension 'spi' or 'spc'
+ * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
+ */
+ public static function get_handler($location, $filename, $extension)
+ {
+ $type = explode(':', $location, 2);
+ $type = $type[0];
+ if (!empty(self::$handlers[$type]))
+ {
+ $class = self::$handlers[$type];
+ return new $class($location, $filename, $extension);
+ }
+
+ return new SimplePie_Cache_File($location, $filename, $extension);
+ }
+
+ /**
+ * Create a new SimplePie_Cache object
+ *
+ * @deprecated Use {@see get_handler} instead
+ */
+ public function create($location, $filename, $extension)
+ {
+ trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
+ return self::get_handler($location, $filename, $extension);
+ }
+
+ /**
+ * Register a handler
+ *
+ * @param string $type DSN type to register for
+ * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
+ */
+ public static function register($type, $class)
+ {
+ self::$handlers[$type] = $class;
+ }
+
+ /**
+ * Parse a URL into an array
+ *
+ * @param string $url
+ * @return array
+ */
+ public static function parse_URL($url)
+ {
+ $params = parse_url($url);
+ $params['extras'] = array();
+ if (isset($params['query']))
+ {
+ parse_str($params['query'], $params['extras']);
+ }
+ return $params;
+ }
+}
+
+/**
+ * Handles `<media:text>` captions as defined in Media RSS.
+ *
+ * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_caption_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Caption
+{
+ /**
+ * Content type
+ *
+ * @var string
+ * @see get_type()
+ */
+ var $type;
+
+ /**
+ * Language
+ *
+ * @var string
+ * @see get_language()
+ */
+ var $lang;
+
+ /**
+ * Start time
+ *
+ * @var string
+ * @see get_starttime()
+ */
+ var $startTime;
+
+ /**
+ * End time
+ *
+ * @var string
+ * @see get_endtime()
+ */
+ var $endTime;
+
+ /**
+ * Caption text
+ *
+ * @var string
+ * @see get_text()
+ */
+ var $text;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
+ {
+ $this->type = $type;
+ $this->lang = $lang;
+ $this->startTime = $startTime;
+ $this->endTime = $endTime;
+ $this->text = $text;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the end time
+ *
+ * @return string|null Time in the format 'hh:mm:ss.SSS'
+ */
+ public function get_endtime()
+ {
+ if ($this->endTime !== null)
+ {
+ return $this->endTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the language
+ *
+ * @link http://tools.ietf.org/html/rfc3066
+ * @return string|null Language code as per RFC 3066
+ */
+ public function get_language()
+ {
+ if ($this->lang !== null)
+ {
+ return $this->lang;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the start time
+ *
+ * @return string|null Time in the format 'hh:mm:ss.SSS'
+ */
+ public function get_starttime()
+ {
+ if ($this->startTime !== null)
+ {
+ return $this->startTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the text of the caption
+ *
+ * @return string|null
+ */
+ public function get_text()
+ {
+ if ($this->text !== null)
+ {
+ return $this->text;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the content type (not MIME type)
+ *
+ * @return string|null Either 'text' or 'html'
+ */
+ public function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * Manages all category-related data
+ *
+ * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_category_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Category
+{
+ /**
+ * Category identifier
+ *
+ * @var string
+ * @see get_term
+ */
+ var $term;
+
+ /**
+ * Categorization scheme identifier
+ *
+ * @var string
+ * @see get_scheme()
+ */
+ var $scheme;
+
+ /**
+ * Human readable label
+ *
+ * @var string
+ * @see get_label()
+ */
+ var $label;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * @param string $term
+ * @param string $scheme
+ * @param string $label
+ */
+ public function __construct($term = null, $scheme = null, $label = null)
+ {
+ $this->term = $term;
+ $this->scheme = $scheme;
+ $this->label = $label;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the category identifier
+ *
+ * @return string|null
+ */
+ public function get_term()
+ {
+ if ($this->term !== null)
+ {
+ return $this->term;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the categorization scheme identifier
+ *
+ * @return string|null
+ */
+ public function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the human readable label
+ *
+ * @return string|null
+ */
+ public function get_label()
+ {
+ if ($this->label !== null)
+ {
+ return $this->label;
+ }
+ else
+ {
+ return $this->get_term();
+ }
+ }
+}
+
+/**
+ * Content-type sniffing
+ *
+ * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
+ *
+ * This is used since we can't always trust Content-Type headers, and is based
+ * upon the HTML5 parsing rules.
+ *
+ *
+ * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ */
+class SimplePie_Content_Type_Sniffer
+{
+ /**
+ * File object
+ *
+ * @var SimplePie_File
+ */
+ var $file;
+
+ /**
+ * Create an instance of the class with the input file
+ *
+ * @param SimplePie_Content_Type_Sniffer $file Input file
+ */
+ public function __construct($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Get the Content-Type of the specified file
+ *
+ * @return string Actual Content-Type
+ */
+ public function get_type()
+ {
+ if (isset($this->file->headers['content-type']))
+ {
+ if (!isset($this->file->headers['content-encoding'])
+ && ($this->file->headers['content-type'] === 'text/plain'
+ || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
+ || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
+ || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
+ {
+ return $this->text_or_binary();
+ }
+
+ if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
+ {
+ $official = substr($this->file->headers['content-type'], 0, $pos);
+ }
+ else
+ {
+ $official = $this->file->headers['content-type'];
+ }
+ $official = trim(strtolower($official));
+
+ if ($official === 'unknown/unknown'
+ || $official === 'application/unknown')
+ {
+ return $this->unknown();
+ }
+ elseif (substr($official, -4) === '+xml'
+ || $official === 'text/xml'
+ || $official === 'application/xml')
+ {
+ return $official;
+ }
+ elseif (substr($official, 0, 6) === 'image/')
+ {
+ if ($return = $this->image())
+ {
+ return $return;
+ }
+ else
+ {
+ return $official;
+ }
+ }
+ elseif ($official === 'text/html')
+ {
+ return $this->feed_or_html();
+ }
+ else
+ {
+ return $official;
+ }
+ }
+ else
+ {
+ return $this->unknown();
+ }
+ }
+
+ /**
+ * Sniff text or binary
+ *
+ * @return string Actual Content-Type
+ */
+ public function text_or_binary()
+ {
+ if (substr($this->file->body, 0, 2) === "\xFE\xFF"
+ || substr($this->file->body, 0, 2) === "\xFF\xFE"
+ || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
+ || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
+ {
+ return 'text/plain';
+ }
+ elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
+ {
+ return 'application/octect-stream';
+ }
+ else
+ {
+ return 'text/plain';
+ }
+ }
+
+ /**
+ * Sniff unknown
+ *
+ * @return string Actual Content-Type
+ */
+ public function unknown()
+ {
+ $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
+ if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
+ || strtolower(substr($this->file->body, $ws, 5)) === '<html'
+ || strtolower(substr($this->file->body, $ws, 7)) === '<script')
+ {
+ return 'text/html';
+ }
+ elseif (substr($this->file->body, 0, 5) === '%PDF-')
+ {
+ return 'application/pdf';
+ }
+ elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
+ {
+ return 'application/postscript';
+ }
+ elseif (substr($this->file->body, 0, 6) === 'GIF87a'
+ || substr($this->file->body, 0, 6) === 'GIF89a')
+ {
+ return 'image/gif';
+ }
+ elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+ {
+ return 'image/png';
+ }
+ elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+ {
+ return 'image/jpeg';
+ }
+ elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+ {
+ return 'image/bmp';
+ }
+ elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
+ {
+ return 'image/vnd.microsoft.icon';
+ }
+ else
+ {
+ return $this->text_or_binary();
+ }
+ }
+
+ /**
+ * Sniff images
+ *
+ * @return string Actual Content-Type
+ */
+ public function image()
+ {
+ if (substr($this->file->body, 0, 6) === 'GIF87a'
+ || substr($this->file->body, 0, 6) === 'GIF89a')
+ {
+ return 'image/gif';
+ }
+ elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+ {
+ return 'image/png';
+ }
+ elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+ {
+ return 'image/jpeg';
+ }
+ elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+ {
+ return 'image/bmp';
+ }
+ elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
+ {
+ return 'image/vnd.microsoft.icon';
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Sniff HTML
+ *
+ * @return string Actual Content-Type
+ */
+ public function feed_or_html()
+ {
+ $len = strlen($this->file->body);
+ $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
+
+ while ($pos < $len)
+ {
+ switch ($this->file->body[$pos])
+ {
+ case "\x09":
+ case "\x0A":
+ case "\x0D":
+ case "\x20":
+ $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
+ continue 2;
+
+ case '<':
+ $pos++;
+ break;
+
+ default:
+ return 'text/html';
+ }
+
+ if (substr($this->file->body, $pos, 3) === '!--')
+ {
+ $pos += 3;
+ if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
+ {
+ $pos += 3;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 1) === '!')
+ {
+ if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
+ {
+ $pos++;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 1) === '?')
+ {
+ if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
+ {
+ $pos += 2;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 3) === 'rss'
+ || substr($this->file->body, $pos, 7) === 'rdf:RDF')
+ {
+ return 'application/rss+xml';
+ }
+ elseif (substr($this->file->body, $pos, 4) === 'feed')
+ {
+ return 'application/atom+xml';
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+
+ return 'text/html';
+ }
+}
+
+/**
+ * Manages `<media:copyright>` copyright tags as defined in Media RSS
+ *
+ * Used by {@see SimplePie_Enclosure::get_copyright()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_copyright_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Copyright
+{
+ /**
+ * Copyright URL
+ *
+ * @var string
+ * @see get_url()
+ */
+ var $url;
+
+ /**
+ * Attribution
+ *
+ * @var string
+ * @see get_attribution()
+ */
+ var $label;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($url = null, $label = null)
+ {
+ $this->url = $url;
+ $this->label = $label;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the copyright URL
+ *
+ * @return string|null URL to copyright information
+ */
+ public function get_url()
+ {
+ if ($this->url !== null)
+ {
+ return $this->url;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the attribution text
+ *
+ * @return string|null
+ */
+ public function get_attribution()
+ {
+ if ($this->label !== null)
+ {
+ return $this->label;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * SimplePie class.
+ *
+ * Class for backward compatibility.
+ *
+ * @deprecated Use {@see SimplePie} directly
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Core extends SimplePie
+{
+
+}
+
+/**
+ * Handles `<media:credit>` as defined in Media RSS
+ *
+ * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_credit_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Credit
+{
+ /**
+ * Credited role
+ *
+ * @var string
+ * @see get_role()
+ */
+ var $role;
+
+ /**
+ * Organizational scheme
+ *
+ * @var string
+ * @see get_scheme()
+ */
+ var $scheme;
+
+ /**
+ * Credited name
+ *
+ * @var string
+ * @see get_name()
+ */
+ var $name;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($role = null, $scheme = null, $name = null)
+ {
+ $this->role = $role;
+ $this->scheme = $scheme;
+ $this->name = $name;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the role of the person receiving credit
+ *
+ * @return string|null
+ */
+ public function get_role()
+ {
+ if ($this->role !== null)
+ {
+ return $this->role;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the organizational scheme
+ *
+ * @return string|null
+ */
+ public function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the credited person/entity's name
+ *
+ * @return string|null
+ */
+ public function get_name()
+ {
+ if ($this->name !== null)
+ {
+ return $this->name;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * Decode HTML Entities
+ *
+ * This implements HTML5 as of revision 967 (2007-06-28)
+ *
+ * @deprecated Use DOMDocument instead!
+ * @package SimplePie
+ */
+class SimplePie_Decode_HTML_Entities
+{
+ /**
+ * Data to be parsed
+ *
+ * @access private
+ * @var string
+ */
+ var $data = '';
+
+ /**
+ * Currently consumed bytes
+ *
+ * @access private
+ * @var string
+ */
+ var $consumed = '';
+
+ /**
+ * Position of the current byte being parsed
+ *
+ * @access private
+ * @var int
+ */
+ var $position = 0;
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @access public
+ * @param string $data Input data
+ */
+ public function __construct($data)
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @access public
+ * @return string Output data
+ */
+ public function parse()
+ {
+ while (($this->position = strpos($this->data, '&', $this->position)) !== false)
+ {
+ $this->consume();
+ $this->entity();
+ $this->consumed = '';
+ }
+ return $this->data;
+ }
+
+ /**
+ * Consume the next byte
+ *
+ * @access private
+ * @return mixed The next byte, or false, if there is no more data
+ */
+ public function consume()
+ {
+ if (isset($this->data[$this->position]))
+ {
+ $this->consumed .= $this->data[$this->position];
+ return $this->data[$this->position++];
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Consume a range of characters
+ *
+ * @access private
+ * @param string $chars Characters to consume
+ * @return mixed A series of characters that match the range, or false
+ */
+ public function consume_range($chars)
+ {
+ if ($len = strspn($this->data, $chars, $this->position))
+ {
+ $data = substr($this->data, $this->position, $len);
+ $this->consumed .= $data;
+ $this->position += $len;
+ return $data;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Unconsume one byte
+ *
+ * @access private
+ */
+ public function unconsume()
+ {
+ $this->consumed = substr($this->consumed, 0, -1);
+ $this->position--;
+ }
+
+ /**
+ * Decode an entity
+ *
+ * @access private
+ */
+ public function entity()
+ {
+ switch ($this->consume())
+ {
+ case "\x09":
+ case "\x0A":
+ case "\x0B":
+ case "\x0B":
+ case "\x0C":
+ case "\x20":
+ case "\x3C":
+ case "\x26":
+ case false:
+ break;
+
+ case "\x23":
+ switch ($this->consume())
+ {
+ case "\x78":
+ case "\x58":
+ $range = '0123456789ABCDEFabcdef';
+ $hex = true;
+ break;
+
+ default:
+ $range = '0123456789';
+ $hex = false;
+ $this->unconsume();
+ break;
+ }
+
+ if ($codepoint = $this->consume_range($range))
+ {
+ static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
+
+ if ($hex)
+ {
+ $codepoint = hexdec($codepoint);
+ }
+ else
+ {
+ $codepoint = intval($codepoint);
+ }
+
+ if (isset($windows_1252_specials[$codepoint]))
+ {
+ $replacement = $windows_1252_specials[$codepoint];
+ }
+ else
+ {
+ $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
+ }
+
+ if (!in_array($this->consume(), array(';', false), true))
+ {
+ $this->unconsume();
+ }
+
+ $consumed_length = strlen($this->consumed);
+ $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
+ $this->position += strlen($replacement) - $consumed_length;
+ }
+ break;
+
+ default:
+ static $entities = array(
+ 'Aacute' => "\xC3\x81",
+ 'aacute' => "\xC3\xA1",
+ 'Aacute;' => "\xC3\x81",
+ 'aacute;' => "\xC3\xA1",
+ 'Acirc' => "\xC3\x82",
+ 'acirc' => "\xC3\xA2",
+ 'Acirc;' => "\xC3\x82",
+ 'acirc;' => "\xC3\xA2",
+ 'acute' => "\xC2\xB4",
+ 'acute;' => "\xC2\xB4",
+ 'AElig' => "\xC3\x86",
+ 'aelig' => "\xC3\xA6",
+ 'AElig;' => "\xC3\x86",
+ 'aelig;' => "\xC3\xA6",
+ 'Agrave' => "\xC3\x80",
+ 'agrave' => "\xC3\xA0",
+ 'Agrave;' => "\xC3\x80",
+ 'agrave;' => "\xC3\xA0",
+ 'alefsym;' => "\xE2\x84\xB5",
+ 'Alpha;' => "\xCE\x91",
+ 'alpha;' => "\xCE\xB1",
+ 'AMP' => "\x26",
+ 'amp' => "\x26",
+ 'AMP;' => "\x26",
+ 'amp;' => "\x26",
+ 'and;' => "\xE2\x88\xA7",
+ 'ang;' => "\xE2\x88\xA0",
+ 'apos;' => "\x27",
+ 'Aring' => "\xC3\x85",
+ 'aring' => "\xC3\xA5",
+ 'Aring;' => "\xC3\x85",
+ 'aring;' => "\xC3\xA5",
+ 'asymp;' => "\xE2\x89\x88",
+ 'Atilde' => "\xC3\x83",
+ 'atilde' => "\xC3\xA3",
+ 'Atilde;' => "\xC3\x83",
+ 'atilde;' => "\xC3\xA3",
+ 'Auml' => "\xC3\x84",
+ 'auml' => "\xC3\xA4",
+ 'Auml;' => "\xC3\x84",
+ 'auml;' => "\xC3\xA4",
+ 'bdquo;' => "\xE2\x80\x9E",
+ 'Beta;' => "\xCE\x92",
+ 'beta;' => "\xCE\xB2",
+ 'brvbar' => "\xC2\xA6",
+ 'brvbar;' => "\xC2\xA6",
+ 'bull;' => "\xE2\x80\xA2",
+ 'cap;' => "\xE2\x88\xA9",
+ 'Ccedil' => "\xC3\x87",
+ 'ccedil' => "\xC3\xA7",
+ 'Ccedil;' => "\xC3\x87",
+ 'ccedil;' => "\xC3\xA7",
+ 'cedil' => "\xC2\xB8",
+ 'cedil;' => "\xC2\xB8",
+ 'cent' => "\xC2\xA2",
+ 'cent;' => "\xC2\xA2",
+ 'Chi;' => "\xCE\xA7",
+ 'chi;' => "\xCF\x87",
+ 'circ;' => "\xCB\x86",
+ 'clubs;' => "\xE2\x99\xA3",
+ 'cong;' => "\xE2\x89\x85",
+ 'COPY' => "\xC2\xA9",
+ 'copy' => "\xC2\xA9",
+ 'COPY;' => "\xC2\xA9",
+ 'copy;' => "\xC2\xA9",
+ 'crarr;' => "\xE2\x86\xB5",
+ 'cup;' => "\xE2\x88\xAA",
+ 'curren' => "\xC2\xA4",
+ 'curren;' => "\xC2\xA4",
+ 'Dagger;' => "\xE2\x80\xA1",
+ 'dagger;' => "\xE2\x80\xA0",
+ 'dArr;' => "\xE2\x87\x93",
+ 'darr;' => "\xE2\x86\x93",
+ 'deg' => "\xC2\xB0",
+ 'deg;' => "\xC2\xB0",
+ 'Delta;' => "\xCE\x94",
+ 'delta;' => "\xCE\xB4",
+ 'diams;' => "\xE2\x99\xA6",
+ 'divide' => "\xC3\xB7",
+ 'divide;' => "\xC3\xB7",
+ 'Eacute' => "\xC3\x89",
+ 'eacute' => "\xC3\xA9",
+ 'Eacute;' => "\xC3\x89",
+ 'eacute;' => "\xC3\xA9",
+ 'Ecirc' => "\xC3\x8A",
+ 'ecirc' => "\xC3\xAA",
+ 'Ecirc;' => "\xC3\x8A",
+ 'ecirc;' => "\xC3\xAA",
+ 'Egrave' => "\xC3\x88",
+ 'egrave' => "\xC3\xA8",
+ 'Egrave;' => "\xC3\x88",
+ 'egrave;' => "\xC3\xA8",
+ 'empty;' => "\xE2\x88\x85",
+ 'emsp;' => "\xE2\x80\x83",
+ 'ensp;' => "\xE2\x80\x82",
+ 'Epsilon;' => "\xCE\x95",
+ 'epsilon;' => "\xCE\xB5",
+ 'equiv;' => "\xE2\x89\xA1",
+ 'Eta;' => "\xCE\x97",
+ 'eta;' => "\xCE\xB7",
+ 'ETH' => "\xC3\x90",
+ 'eth' => "\xC3\xB0",
+ 'ETH;' => "\xC3\x90",
+ 'eth;' => "\xC3\xB0",
+ 'Euml' => "\xC3\x8B",
+ 'euml' => "\xC3\xAB",
+ 'Euml;' => "\xC3\x8B",
+ 'euml;' => "\xC3\xAB",
+ 'euro;' => "\xE2\x82\xAC",
+ 'exist;' => "\xE2\x88\x83",
+ 'fnof;' => "\xC6\x92",
+ 'forall;' => "\xE2\x88\x80",
+ 'frac12' => "\xC2\xBD",
+ 'frac12;' => "\xC2\xBD",
+ 'frac14' => "\xC2\xBC",
+ 'frac14;' => "\xC2\xBC",
+ 'frac34' => "\xC2\xBE",
+ 'frac34;' => "\xC2\xBE",
+ 'frasl;' => "\xE2\x81\x84",
+ 'Gamma;' => "\xCE\x93",
+ 'gamma;' => "\xCE\xB3",
+ 'ge;' => "\xE2\x89\xA5",
+ 'GT' => "\x3E",
+ 'gt' => "\x3E",
+ 'GT;' => "\x3E",
+ 'gt;' => "\x3E",
+ 'hArr;' => "\xE2\x87\x94",
+ 'harr;' => "\xE2\x86\x94",
+ 'hearts;' => "\xE2\x99\xA5",
+ 'hellip;' => "\xE2\x80\xA6",
+ 'Iacute' => "\xC3\x8D",
+ 'iacute' => "\xC3\xAD",
+ 'Iacute;' => "\xC3\x8D",
+ 'iacute;' => "\xC3\xAD",
+ 'Icirc' => "\xC3\x8E",
+ 'icirc' => "\xC3\xAE",
+ 'Icirc;' => "\xC3\x8E",
+ 'icirc;' => "\xC3\xAE",
+ 'iexcl' => "\xC2\xA1",
+ 'iexcl;' => "\xC2\xA1",
+ 'Igrave' => "\xC3\x8C",
+ 'igrave' => "\xC3\xAC",
+ 'Igrave;' => "\xC3\x8C",
+ 'igrave;' => "\xC3\xAC",
+ 'image;' => "\xE2\x84\x91",
+ 'infin;' => "\xE2\x88\x9E",
+ 'int;' => "\xE2\x88\xAB",
+ 'Iota;' => "\xCE\x99",
+ 'iota;' => "\xCE\xB9",
+ 'iquest' => "\xC2\xBF",
+ 'iquest;' => "\xC2\xBF",
+ 'isin;' => "\xE2\x88\x88",
+ 'Iuml' => "\xC3\x8F",
+ 'iuml' => "\xC3\xAF",
+ 'Iuml;' => "\xC3\x8F",
+ 'iuml;' => "\xC3\xAF",
+ 'Kappa;' => "\xCE\x9A",
+ 'kappa;' => "\xCE\xBA",
+ 'Lambda;' => "\xCE\x9B",
+ 'lambda;' => "\xCE\xBB",
+ 'lang;' => "\xE3\x80\x88",
+ 'laquo' => "\xC2\xAB",
+ 'laquo;' => "\xC2\xAB",
+ 'lArr;' => "\xE2\x87\x90",
+ 'larr;' => "\xE2\x86\x90",
+ 'lceil;' => "\xE2\x8C\x88",
+ 'ldquo;' => "\xE2\x80\x9C",
+ 'le;' => "\xE2\x89\xA4",
+ 'lfloor;' => "\xE2\x8C\x8A",
+ 'lowast;' => "\xE2\x88\x97",
+ 'loz;' => "\xE2\x97\x8A",
+ 'lrm;' => "\xE2\x80\x8E",
+ 'lsaquo;' => "\xE2\x80\xB9",
+ 'lsquo;' => "\xE2\x80\x98",
+ 'LT' => "\x3C",
+ 'lt' => "\x3C",
+ 'LT;' => "\x3C",
+ 'lt;' => "\x3C",
+ 'macr' => "\xC2\xAF",
+ 'macr;' => "\xC2\xAF",
+ 'mdash;' => "\xE2\x80\x94",
+ 'micro' => "\xC2\xB5",
+ 'micro;' => "\xC2\xB5",
+ 'middot' => "\xC2\xB7",
+ 'middot;' => "\xC2\xB7",
+ 'minus;' => "\xE2\x88\x92",
+ 'Mu;' => "\xCE\x9C",
+ 'mu;' => "\xCE\xBC",
+ 'nabla;' => "\xE2\x88\x87",
+ 'nbsp' => "\xC2\xA0",
+ 'nbsp;' => "\xC2\xA0",
+ 'ndash;' => "\xE2\x80\x93",
+ 'ne;' => "\xE2\x89\xA0",
+ 'ni;' => "\xE2\x88\x8B",
+ 'not' => "\xC2\xAC",
+ 'not;' => "\xC2\xAC",
+ 'notin;' => "\xE2\x88\x89",
+ 'nsub;' => "\xE2\x8A\x84",
+ 'Ntilde' => "\xC3\x91",
+ 'ntilde' => "\xC3\xB1",
+ 'Ntilde;' => "\xC3\x91",
+ 'ntilde;' => "\xC3\xB1",
+ 'Nu;' => "\xCE\x9D",
+ 'nu;' => "\xCE\xBD",
+ 'Oacute' => "\xC3\x93",
+ 'oacute' => "\xC3\xB3",
+ 'Oacute;' => "\xC3\x93",
+ 'oacute;' => "\xC3\xB3",
+ 'Ocirc' => "\xC3\x94",
+ 'ocirc' => "\xC3\xB4",
+ 'Ocirc;' => "\xC3\x94",
+ 'ocirc;' => "\xC3\xB4",
+ 'OElig;' => "\xC5\x92",
+ 'oelig;' => "\xC5\x93",
+ 'Ograve' => "\xC3\x92",
+ 'ograve' => "\xC3\xB2",
+ 'Ograve;' => "\xC3\x92",
+ 'ograve;' => "\xC3\xB2",
+ 'oline;' => "\xE2\x80\xBE",
+ 'Omega;' => "\xCE\xA9",
+ 'omega;' => "\xCF\x89",
+ 'Omicron;' => "\xCE\x9F",
+ 'omicron;' => "\xCE\xBF",
+ 'oplus;' => "\xE2\x8A\x95",
+ 'or;' => "\xE2\x88\xA8",
+ 'ordf' => "\xC2\xAA",
+ 'ordf;' => "\xC2\xAA",
+ 'ordm' => "\xC2\xBA",
+ 'ordm;' => "\xC2\xBA",
+ 'Oslash' => "\xC3\x98",
+ 'oslash' => "\xC3\xB8",
+ 'Oslash;' => "\xC3\x98",
+ 'oslash;' => "\xC3\xB8",
+ 'Otilde' => "\xC3\x95",
+ 'otilde' => "\xC3\xB5",
+ 'Otilde;' => "\xC3\x95",
+ 'otilde;' => "\xC3\xB5",
+ 'otimes;' => "\xE2\x8A\x97",
+ 'Ouml' => "\xC3\x96",
+ 'ouml' => "\xC3\xB6",
+ 'Ouml;' => "\xC3\x96",
+ 'ouml;' => "\xC3\xB6",
+ 'para' => "\xC2\xB6",
+ 'para;' => "\xC2\xB6",
+ 'part;' => "\xE2\x88\x82",
+ 'permil;' => "\xE2\x80\xB0",
+ 'perp;' => "\xE2\x8A\xA5",
+ 'Phi;' => "\xCE\xA6",
+ 'phi;' => "\xCF\x86",
+ 'Pi;' => "\xCE\xA0",
+ 'pi;' => "\xCF\x80",
+ 'piv;' => "\xCF\x96",
+ 'plusmn' => "\xC2\xB1",
+ 'plusmn;' => "\xC2\xB1",
+ 'pound' => "\xC2\xA3",
+ 'pound;' => "\xC2\xA3",
+ 'Prime;' => "\xE2\x80\xB3",
+ 'prime;' => "\xE2\x80\xB2",
+ 'prod;' => "\xE2\x88\x8F",
+ 'prop;' => "\xE2\x88\x9D",
+ 'Psi;' => "\xCE\xA8",
+ 'psi;' => "\xCF\x88",
+ 'QUOT' => "\x22",
+ 'quot' => "\x22",
+ 'QUOT;' => "\x22",
+ 'quot;' => "\x22",
+ 'radic;' => "\xE2\x88\x9A",
+ 'rang;' => "\xE3\x80\x89",
+ 'raquo' => "\xC2\xBB",
+ 'raquo;' => "\xC2\xBB",
+ 'rArr;' => "\xE2\x87\x92",
+ 'rarr;' => "\xE2\x86\x92",
+ 'rceil;' => "\xE2\x8C\x89",
+ 'rdquo;' => "\xE2\x80\x9D",
+ 'real;' => "\xE2\x84\x9C",
+ 'REG' => "\xC2\xAE",
+ 'reg' => "\xC2\xAE",
+ 'REG;' => "\xC2\xAE",
+ 'reg;' => "\xC2\xAE",
+ 'rfloor;' => "\xE2\x8C\x8B",
+ 'Rho;' => "\xCE\xA1",
+ 'rho;' => "\xCF\x81",
+ 'rlm;' => "\xE2\x80\x8F",
+ 'rsaquo;' => "\xE2\x80\xBA",
+ 'rsquo;' => "\xE2\x80\x99",
+ 'sbquo;' => "\xE2\x80\x9A",
+ 'Scaron;' => "\xC5\xA0",
+ 'scaron;' => "\xC5\xA1",
+ 'sdot;' => "\xE2\x8B\x85",
+ 'sect' => "\xC2\xA7",
+ 'sect;' => "\xC2\xA7",
+ 'shy' => "\xC2\xAD",
+ 'shy;' => "\xC2\xAD",
+ 'Sigma;' => "\xCE\xA3",
+ 'sigma;' => "\xCF\x83",
+ 'sigmaf;' => "\xCF\x82",
+ 'sim;' => "\xE2\x88\xBC",
+ 'spades;' => "\xE2\x99\xA0",
+ 'sub;' => "\xE2\x8A\x82",
+ 'sube;' => "\xE2\x8A\x86",
+ 'sum;' => "\xE2\x88\x91",
+ 'sup;' => "\xE2\x8A\x83",
+ 'sup1' => "\xC2\xB9",
+ 'sup1;' => "\xC2\xB9",
+ 'sup2' => "\xC2\xB2",
+ 'sup2;' => "\xC2\xB2",
+ 'sup3' => "\xC2\xB3",
+ 'sup3;' => "\xC2\xB3",
+ 'supe;' => "\xE2\x8A\x87",
+ 'szlig' => "\xC3\x9F",
+ 'szlig;' => "\xC3\x9F",
+ 'Tau;' => "\xCE\xA4",
+ 'tau;' => "\xCF\x84",
+ 'there4;' => "\xE2\x88\xB4",
+ 'Theta;' => "\xCE\x98",
+ 'theta;' => "\xCE\xB8",
+ 'thetasym;' => "\xCF\x91",
+ 'thinsp;' => "\xE2\x80\x89",
+ 'THORN' => "\xC3\x9E",
+ 'thorn' => "\xC3\xBE",
+ 'THORN;' => "\xC3\x9E",
+ 'thorn;' => "\xC3\xBE",
+ 'tilde;' => "\xCB\x9C",
+ 'times' => "\xC3\x97",
+ 'times;' => "\xC3\x97",
+ 'TRADE;' => "\xE2\x84\xA2",
+ 'trade;' => "\xE2\x84\xA2",
+ 'Uacute' => "\xC3\x9A",
+ 'uacute' => "\xC3\xBA",
+ 'Uacute;' => "\xC3\x9A",
+ 'uacute;' => "\xC3\xBA",
+ 'uArr;' => "\xE2\x87\x91",
+ 'uarr;' => "\xE2\x86\x91",
+ 'Ucirc' => "\xC3\x9B",
+ 'ucirc' => "\xC3\xBB",
+ 'Ucirc;' => "\xC3\x9B",
+ 'ucirc;' => "\xC3\xBB",
+ 'Ugrave' => "\xC3\x99",
+ 'ugrave' => "\xC3\xB9",
+ 'Ugrave;' => "\xC3\x99",
+ 'ugrave;' => "\xC3\xB9",
+ 'uml' => "\xC2\xA8",
+ 'uml;' => "\xC2\xA8",
+ 'upsih;' => "\xCF\x92",
+ 'Upsilon;' => "\xCE\xA5",
+ 'upsilon;' => "\xCF\x85",
+ 'Uuml' => "\xC3\x9C",
+ 'uuml' => "\xC3\xBC",
+ 'Uuml;' => "\xC3\x9C",
+ 'uuml;' => "\xC3\xBC",
+ 'weierp;' => "\xE2\x84\x98",
+ 'Xi;' => "\xCE\x9E",
+ 'xi;' => "\xCE\xBE",
+ 'Yacute' => "\xC3\x9D",
+ 'yacute' => "\xC3\xBD",
+ 'Yacute;' => "\xC3\x9D",
+ 'yacute;' => "\xC3\xBD",
+ 'yen' => "\xC2\xA5",
+ 'yen;' => "\xC2\xA5",
+ 'yuml' => "\xC3\xBF",
+ 'Yuml;' => "\xC5\xB8",
+ 'yuml;' => "\xC3\xBF",
+ 'Zeta;' => "\xCE\x96",
+ 'zeta;' => "\xCE\xB6",
+ 'zwj;' => "\xE2\x80\x8D",
+ 'zwnj;' => "\xE2\x80\x8C"
+ );
+
+ for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
+ {
+ $consumed = substr($this->consumed, 1);
+ if (isset($entities[$consumed]))
+ {
+ $match = $consumed;
+ }
+ }
+
+ if ($match !== null)
+ {
+ $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
+ $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
+ }
+ break;
+ }
+ }
+}
+
+/**
+ * Handles everything related to enclosures (including Media RSS and iTunes RSS)
+ *
+ * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Enclosure
+{
+ /**
+ * @var string
+ * @see get_bitrate()
+ */
+ var $bitrate;
+
+ /**
+ * @var array
+ * @see get_captions()
+ */
+ var $captions;
+
+ /**
+ * @var array
+ * @see get_categories()
+ */
+ var $categories;
+
+ /**
+ * @var int
+ * @see get_channels()
+ */
+ var $channels;
+
+ /**
+ * @var SimplePie_Copyright
+ * @see get_copyright()
+ */
+ var $copyright;
+
+ /**
+ * @var array
+ * @see get_credits()
+ */
+ var $credits;
+
+ /**
+ * @var string
+ * @see get_description()
+ */
+ var $description;
+
+ /**
+ * @var int
+ * @see get_duration()
+ */
+ var $duration;
+
+ /**
+ * @var string
+ * @see get_expression()
+ */
+ var $expression;
+
+ /**
+ * @var string
+ * @see get_framerate()
+ */
+ var $framerate;
+
+ /**
+ * @var string
+ * @see get_handler()
+ */
+ var $handler;
+
+ /**
+ * @var array
+ * @see get_hashes()
+ */
+ var $hashes;
+
+ /**
+ * @var string
+ * @see get_height()
+ */
+ var $height;
+
+ /**
+ * @deprecated
+ * @var null
+ */
+ var $javascript;
+
+ /**
+ * @var array
+ * @see get_keywords()
+ */
+ var $keywords;
+
+ /**
+ * @var string
+ * @see get_language()
+ */
+ var $lang;
+
+ /**
+ * @var string
+ * @see get_length()
+ */
+ var $length;
+
+ /**
+ * @var string
+ * @see get_link()
+ */
+ var $link;
+
+ /**
+ * @var string
+ * @see get_medium()
+ */
+ var $medium;
+
+ /**
+ * @var string
+ * @see get_player()
+ */
+ var $player;
+
+ /**
+ * @var array
+ * @see get_ratings()
+ */
+ var $ratings;
+
+ /**
+ * @var array
+ * @see get_restrictions()
+ */
+ var $restrictions;
+
+ /**
+ * @var string
+ * @see get_sampling_rate()
+ */
+ var $samplingrate;
+
+ /**
+ * @var array
+ * @see get_thumbnails()
+ */
+ var $thumbnails;
+
+ /**
+ * @var string
+ * @see get_title()
+ */
+ var $title;
+
+ /**
+ * @var string
+ * @see get_type()
+ */
+ var $type;
+
+ /**
+ * @var string
+ * @see get_width()
+ */
+ var $width;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ *
+ * @uses idna_convert If available, this will convert an IDN
+ */
+ public function __construct($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
+ {
+ $this->bitrate = $bitrate;
+ $this->captions = $captions;
+ $this->categories = $categories;
+ $this->channels = $channels;
+ $this->copyright = $copyright;
+ $this->credits = $credits;
+ $this->description = $description;
+ $this->duration = $duration;
+ $this->expression = $expression;
+ $this->framerate = $framerate;
+ $this->hashes = $hashes;
+ $this->height = $height;
+ $this->keywords = $keywords;
+ $this->lang = $lang;
+ $this->length = $length;
+ $this->link = $link;
+ $this->medium = $medium;
+ $this->player = $player;
+ $this->ratings = $ratings;
+ $this->restrictions = $restrictions;
+ $this->samplingrate = $samplingrate;
+ $this->thumbnails = $thumbnails;
+ $this->title = $title;
+ $this->type = $type;
+ $this->width = $width;
+
+ if (class_exists('idna_convert'))
+ {
+ $idn = new idna_convert();
+ $parsed = SimplePie_Misc::parse_url($link);
+ $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+ }
+ $this->handler = $this->get_handler(); // Needs to load last
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the bitrate
+ *
+ * @return string|null
+ */
+ public function get_bitrate()
+ {
+ if ($this->bitrate !== null)
+ {
+ return $this->bitrate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single caption
+ *
+ * @param int $key
+ * @return SimplePie_Caption|null
+ */
+ public function get_caption($key = 0)
+ {
+ $captions = $this->get_captions();
+ if (isset($captions[$key]))
+ {
+ return $captions[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all captions
+ *
+ * @return array|null Array of {@see SimplePie_Caption} objects
+ */
+ public function get_captions()
+ {
+ if ($this->captions !== null)
+ {
+ return $this->captions;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single category
+ *
+ * @param int $key
+ * @return SimplePie_Category|null
+ */
+ public function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all categories
+ *
+ * @return array|null Array of {@see SimplePie_Category} objects
+ */
+ public function get_categories()
+ {
+ if ($this->categories !== null)
+ {
+ return $this->categories;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the number of audio channels
+ *
+ * @return int|null
+ */
+ public function get_channels()
+ {
+ if ($this->channels !== null)
+ {
+ return $this->channels;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the copyright information
+ *
+ * @return SimplePie_Copyright|null
+ */
+ public function get_copyright()
+ {
+ if ($this->copyright !== null)
+ {
+ return $this->copyright;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single credit
+ *
+ * @param int $key
+ * @return SimplePie_Credit|null
+ */
+ public function get_credit($key = 0)
+ {
+ $credits = $this->get_credits();
+ if (isset($credits[$key]))
+ {
+ return $credits[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all credits
+ *
+ * @return array|null Array of {@see SimplePie_Credit} objects
+ */
+ public function get_credits()
+ {
+ if ($this->credits !== null)
+ {
+ return $this->credits;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the description of the enclosure
+ *
+ * @return string|null
+ */
+ public function get_description()
+ {
+ if ($this->description !== null)
+ {
+ return $this->description;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the duration of the enclosure
+ *
+ * @param string $convert Convert seconds into hh:mm:ss
+ * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
+ */
+ public function get_duration($convert = false)
+ {
+ if ($this->duration !== null)
+ {
+ if ($convert)
+ {
+ $time = SimplePie_Misc::time_hms($this->duration);
+ return $time;
+ }
+ else
+ {
+ return $this->duration;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the expression
+ *
+ * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
+ */
+ public function get_expression()
+ {
+ if ($this->expression !== null)
+ {
+ return $this->expression;
+ }
+ else
+ {
+ return 'full';
+ }
+ }
+
+ /**
+ * Get the file extension
+ *
+ * @return string|null
+ */
+ public function get_extension()
+ {
+ if ($this->link !== null)
+ {
+ $url = SimplePie_Misc::parse_url($this->link);
+ if ($url['path'] !== '')
+ {
+ return pathinfo($url['path'], PATHINFO_EXTENSION);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the framerate (in frames-per-second)
+ *
+ * @return string|null
+ */
+ public function get_framerate()
+ {
+ if ($this->framerate !== null)
+ {
+ return $this->framerate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the preferred handler
+ *
+ * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
+ */
+ public function get_handler()
+ {
+ return $this->get_real_type(true);
+ }
+
+ /**
+ * Get a single hash
+ *
+ * @link http://www.rssboard.org/media-rss#media-hash
+ * @param int $key
+ * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
+ */
+ public function get_hash($key = 0)
+ {
+ $hashes = $this->get_hashes();
+ if (isset($hashes[$key]))
+ {
+ return $hashes[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all credits
+ *
+ * @return array|null Array of strings, see {@see get_hash()}
+ */
+ public function get_hashes()
+ {
+ if ($this->hashes !== null)
+ {
+ return $this->hashes;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the height
+ *
+ * @return string|null
+ */
+ public function get_height()
+ {
+ if ($this->height !== null)
+ {
+ return $this->height;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the language
+ *
+ * @link http://tools.ietf.org/html/rfc3066
+ * @return string|null Language code as per RFC 3066
+ */
+ public function get_language()
+ {
+ if ($this->lang !== null)
+ {
+ return $this->lang;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single keyword
+ *
+ * @param int $key
+ * @return string|null
+ */
+ public function get_keyword($key = 0)
+ {
+ $keywords = $this->get_keywords();
+ if (isset($keywords[$key]))
+ {
+ return $keywords[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all keywords
+ *
+ * @return array|null Array of strings
+ */
+ public function get_keywords()
+ {
+ if ($this->keywords !== null)
+ {
+ return $this->keywords;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get length
+ *
+ * @return float Length in bytes
+ */
+ public function get_length()
+ {
+ if ($this->length !== null)
+ {
+ return $this->length;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the URL
+ *
+ * @return string|null
+ */
+ public function get_link()
+ {
+ if ($this->link !== null)
+ {
+ return urldecode($this->link);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the medium
+ *
+ * @link http://www.rssboard.org/media-rss#media-content
+ * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
+ */
+ public function get_medium()
+ {
+ if ($this->medium !== null)
+ {
+ return $this->medium;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the player URL
+ *
+ * Typically the same as {@see get_permalink()}
+ * @return string|null Player URL
+ */
+ public function get_player()
+ {
+ if ($this->player !== null)
+ {
+ return $this->player;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single rating
+ *
+ * @param int $key
+ * @return SimplePie_Rating|null
+ */
+ public function get_rating($key = 0)
+ {
+ $ratings = $this->get_ratings();
+ if (isset($ratings[$key]))
+ {
+ return $ratings[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all ratings
+ *
+ * @return array|null Array of {@see SimplePie_Rating} objects
+ */
+ public function get_ratings()
+ {
+ if ($this->ratings !== null)
+ {
+ return $this->ratings;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single restriction
+ *
+ * @param int $key
+ * @return SimplePie_Restriction|null
+ */
+ public function get_restriction($key = 0)
+ {
+ $restrictions = $this->get_restrictions();
+ if (isset($restrictions[$key]))
+ {
+ return $restrictions[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all restrictions
+ *
+ * @return array|null Array of {@see SimplePie_Restriction} objects
+ */
+ public function get_restrictions()
+ {
+ if ($this->restrictions !== null)
+ {
+ return $this->restrictions;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the sampling rate (in kHz)
+ *
+ * @return string|null
+ */
+ public function get_sampling_rate()
+ {
+ if ($this->samplingrate !== null)
+ {
+ return $this->samplingrate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the file size (in MiB)
+ *
+ * @return float|null File size in mebibytes (1048 bytes)
+ */
+ public function get_size()
+ {
+ $length = $this->get_length();
+ if ($length !== null)
+ {
+ return round($length/1048576, 2);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single thumbnail
+ *
+ * @param int $key
+ * @return string|null Thumbnail URL
+ */
+ public function get_thumbnail($key = 0)
+ {
+ $thumbnails = $this->get_thumbnails();
+ if (isset($thumbnails[$key]))
+ {
+ return $thumbnails[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all thumbnails
+ *
+ * @return array|null Array of thumbnail URLs
+ */
+ public function get_thumbnails()
+ {
+ if ($this->thumbnails !== null)
+ {
+ return $this->thumbnails;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the title
+ *
+ * @return string|null
+ */
+ public function get_title()
+ {
+ if ($this->title !== null)
+ {
+ return $this->title;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get mimetype of the enclosure
+ *
+ * @see get_real_type()
+ * @return string|null MIME type
+ */
+ public function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the width
+ *
+ * @return string|null
+ */
+ public function get_width()
+ {
+ if ($this->width !== null)
+ {
+ return $this->width;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Embed the enclosure using `<embed>`
+ *
+ * @deprecated Use the second parameter to {@see embed} instead
+ *
+ * @param array|string $options See first paramter to {@see embed}
+ * @return string HTML string to output
+ */
+ public function native_embed($options='')
+ {
+ return $this->embed($options, true);
+ }
+
+ /**
+ * Embed the enclosure using Javascript
+ *
+ * `$options` is an array or comma-separated key:value string, with the
+ * following properties:
+ *
+ * - `alt` (string): Alternate content for when an end-user does not have
+ * the appropriate handler installed or when a file type is
+ * unsupported. Can be any text or HTML. Defaults to blank.
+ * - `altclass` (string): If a file type is unsupported, the end-user will
+ * see the alt text (above) linked directly to the content. That link
+ * will have this value as its class name. Defaults to blank.
+ * - `audio` (string): This is an image that should be used as a
+ * placeholder for audio files before they're loaded (QuickTime-only).
+ * Can be any relative or absolute URL. Defaults to blank.
+ * - `bgcolor` (string): The background color for the media, if not
+ * already transparent. Defaults to `#ffffff`.
+ * - `height` (integer): The height of the embedded media. Accepts any
+ * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
+ * and it is recommended that you use this default.
+ * - `loop` (boolean): Do you want the media to loop when its done?
+ * Defaults to `false`.
+ * - `mediaplayer` (string): The location of the included
+ * `mediaplayer.swf` file. This allows for the playback of Flash Video
+ * (`.flv`) files, and is the default handler for non-Odeo MP3's.
+ * Defaults to blank.
+ * - `video` (string): This is an image that should be used as a
+ * placeholder for video files before they're loaded (QuickTime-only).
+ * Can be any relative or absolute URL. Defaults to blank.
+ * - `width` (integer): The width of the embedded media. Accepts any
+ * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
+ * and it is recommended that you use this default.
+ * - `widescreen` (boolean): Is the enclosure widescreen or standard?
+ * This applies only to video enclosures, and will automatically resize
+ * the content appropriately. Defaults to `false`, implying 4:3 mode.
+ *
+ * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
+ * will default to 480x360 video resolution. Widescreen (16:9) mode with
+ * `width` and `height` set to `auto` will default to 480x270 video resolution.
+ *
+ * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
+ * @param array|string $options Comma-separated key:value list, or array
+ * @param bool $native Use `<embed>`
+ * @return string HTML string to output
+ */
+ public function embed($options = '', $native = false)
+ {
+ // Set up defaults
+ $audio = '';
+ $video = '';
+ $alt = '';
+ $altclass = '';
+ $loop = 'false';
+ $width = 'auto';
+ $height = 'auto';
+ $bgcolor = '#ffffff';
+ $mediaplayer = '';
+ $widescreen = false;
+ $handler = $this->get_handler();
+ $type = $this->get_real_type();
+
+ // Process options and reassign values as necessary
+ if (is_array($options))
+ {
+ extract($options);
+ }
+ else
+ {
+ $options = explode(',', $options);
+ foreach($options as $option)
+ {
+ $opt = explode(':', $option, 2);
+ if (isset($opt[0], $opt[1]))
+ {
+ $opt[0] = trim($opt[0]);
+ $opt[1] = trim($opt[1]);
+ switch ($opt[0])
+ {
+ case 'audio':
+ $audio = $opt[1];
+ break;
+
+ case 'video':
+ $video = $opt[1];
+ break;
+
+ case 'alt':
+ $alt = $opt[1];
+ break;
+
+ case 'altclass':
+ $altclass = $opt[1];
+ break;
+
+ case 'loop':
+ $loop = $opt[1];
+ break;
+
+ case 'width':
+ $width = $opt[1];
+ break;
+
+ case 'height':
+ $height = $opt[1];
+ break;
+
+ case 'bgcolor':
+ $bgcolor = $opt[1];
+ break;
+
+ case 'mediaplayer':
+ $mediaplayer = $opt[1];
+ break;
+
+ case 'widescreen':
+ $widescreen = $opt[1];
+ break;
+ }
+ }
+ }
+ }
+
+ $mime = explode('/', $type, 2);
+ $mime = $mime[0];
+
+ // Process values for 'auto'
+ if ($width === 'auto')
+ {
+ if ($mime === 'video')
+ {
+ if ($height === 'auto')
+ {
+ $width = 480;
+ }
+ elseif ($widescreen)
+ {
+ $width = round((intval($height)/9)*16);
+ }
+ else
+ {
+ $width = round((intval($height)/3)*4);
+ }
+ }
+ else
+ {
+ $width = '100%';
+ }
+ }
+
+ if ($height === 'auto')
+ {
+ if ($mime === 'audio')
+ {
+ $height = 0;
+ }
+ elseif ($mime === 'video')
+ {
+ if ($width === 'auto')
+ {
+ if ($widescreen)
+ {
+ $height = 270;
+ }
+ else
+ {
+ $height = 360;
+ }
+ }
+ elseif ($widescreen)
+ {
+ $height = round((intval($width)/16)*9);
+ }
+ else
+ {
+ $height = round((intval($width)/4)*3);
+ }
+ }
+ else
+ {
+ $height = 376;
+ }
+ }
+ elseif ($mime === 'audio')
+ {
+ $height = 0;
+ }
+
+ // Set proper placeholder value
+ if ($mime === 'audio')
+ {
+ $placeholder = $audio;
+ }
+ elseif ($mime === 'video')
+ {
+ $placeholder = $video;
+ }
+
+ $embed = '';
+
+ // Flash
+ if ($handler === 'flash')
+ {
+ if ($native)
+ {
+ $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
+ }
+ }
+
+ // Flash Media Player file types.
+ // Preferred handler for MP3 file types.
+ elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
+ {
+ $height += 20;
+ if ($native)
+ {
+ $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
+ }
+ }
+
+ // QuickTime 7 file types. Need to test with QuickTime 6.
+ // Only handle MP3's if the Flash Media Player is not present.
+ elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
+ {
+ $height += 16;
+ if ($native)
+ {
+ if ($placeholder !== '')
+ {
+ $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+ }
+ else
+ {
+ $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+ }
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
+ }
+ }
+
+ // Windows Media
+ elseif ($handler === 'wmedia')
+ {
+ $height += 45;
+ if ($native)
+ {
+ $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
+ }
+ }
+
+ // Everything else
+ else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
+
+ return $embed;
+ }
+
+ /**
+ * Get the real media type
+ *
+ * Often, feeds lie to us, necessitating a bit of deeper inspection. This
+ * converts types to their canonical representations based on the file
+ * extension
+ *
+ * @see get_type()
+ * @param bool $find_handler Internal use only, use {@see get_handler()} instead
+ * @return string MIME type
+ */
+ public function get_real_type($find_handler = false)
+ {
+ // Mime-types by handler.
+ $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
+ $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
+ $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
+ $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
+ $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
+
+ if ($this->get_type() !== null)
+ {
+ $type = strtolower($this->type);
+ }
+ else
+ {
+ $type = null;
+ }
+
+ // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
+ if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
+ {
+ switch (strtolower($this->get_extension()))
+ {
+ // Audio mime-types
+ case 'aac':
+ case 'adts':
+ $type = 'audio/acc';
+ break;
+
+ case 'aif':
+ case 'aifc':
+ case 'aiff':
+ case 'cdda':
+ $type = 'audio/aiff';
+ break;
+
+ case 'bwf':
+ $type = 'audio/wav';
+ break;
+
+ case 'kar':
+ case 'mid':
+ case 'midi':
+ case 'smf':
+ $type = 'audio/midi';
+ break;
+
+ case 'm4a':
+ $type = 'audio/x-m4a';
+ break;
+
+ case 'mp3':
+ case 'swa':
+ $type = 'audio/mp3';
+ break;
+
+ case 'wav':
+ $type = 'audio/wav';
+ break;
+
+ case 'wax':
+ $type = 'audio/x-ms-wax';
+ break;
+
+ case 'wma':
+ $type = 'audio/x-ms-wma';
+ break;
+
+ // Video mime-types
+ case '3gp':
+ case '3gpp':
+ $type = 'video/3gpp';
+ break;
+
+ case '3g2':
+ case '3gp2':
+ $type = 'video/3gpp2';
+ break;
+
+ case 'asf':
+ $type = 'video/x-ms-asf';
+ break;
+
+ case 'flv':
+ $type = 'video/x-flv';
+ break;
+
+ case 'm1a':
+ case 'm1s':
+ case 'm1v':
+ case 'm15':
+ case 'm75':
+ case 'mp2':
+ case 'mpa':
+ case 'mpeg':
+ case 'mpg':
+ case 'mpm':
+ case 'mpv':
+ $type = 'video/mpeg';
+ break;
+
+ case 'm4v':
+ $type = 'video/x-m4v';
+ break;
+
+ case 'mov':
+ case 'qt':
+ $type = 'video/quicktime';
+ break;
+
+ case 'mp4':
+ case 'mpg4':
+ $type = 'video/mp4';
+ break;
+
+ case 'sdv':
+ $type = 'video/sd-video';
+ break;
+
+ case 'wm':
+ $type = 'video/x-ms-wm';
+ break;
+
+ case 'wmv':
+ $type = 'video/x-ms-wmv';
+ break;
+
+ case 'wvx':
+ $type = 'video/x-ms-wvx';
+ break;
+
+ // Flash mime-types
+ case 'spl':
+ $type = 'application/futuresplash';
+ break;
+
+ case 'swf':
+ $type = 'application/x-shockwave-flash';
+ break;
+ }
+ }
+
+ if ($find_handler)
+ {
+ if (in_array($type, $types_flash))
+ {
+ return 'flash';
+ }
+ elseif (in_array($type, $types_fmedia))
+ {
+ return 'fmedia';
+ }
+ elseif (in_array($type, $types_quicktime))
+ {
+ return 'quicktime';
+ }
+ elseif (in_array($type, $types_wmedia))
+ {
+ return 'wmedia';
+ }
+ elseif (in_array($type, $types_mp3))
+ {
+ return 'mp3';
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return $type;
+ }
+ }
+}
+
+/**
+ * General SimplePie exception class
+ *
+ * @package SimplePie
+ */
+class SimplePie_Exception extends Exception
+{
+}
+
+/**
+ * Used for fetching remote files and reading local files
+ *
+ * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
+ *
+ * This class can be overloaded with {@see SimplePie::set_file_class()}
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ * @todo Move to properly supporting RFC2616 (HTTP/1.1)
+ */
+class SimplePie_File
+{
+ var $url;
+ var $useragent;
+ var $success = true;
+ var $headers = array();
+ var $body;
+ var $status_code;
+ var $redirects = 0;
+ var $error;
+ var $method = SIMPLEPIE_FILE_SOURCE_NONE;
+
+ public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
+ {
+ if (class_exists('idna_convert'))
+ {
+ $idn = new idna_convert();
+ $parsed = SimplePie_Misc::parse_url($url);
+ $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+ }
+ $this->url = $url;
+ $this->useragent = $useragent;
+ if (preg_match('/^http(s)?:\/\//i', $url))
+ {
+ if ($useragent === null)
+ {
+ $useragent = ini_get('user_agent');
+ $this->useragent = $useragent;
+ }
+ if (!is_array($headers))
+ {
+ $headers = array();
+ }
+ if (!$force_fsockopen && function_exists('curl_exec'))
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
+ $fp = curl_init();
+ $headers2 = array();
+ foreach ($headers as $key => $value)
+ {
+ $headers2[] = "$key: $value";
+ }
+ if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
+ {
+ curl_setopt($fp, CURLOPT_ENCODING, '');
+ }
+ curl_setopt($fp, CURLOPT_URL, $url);
+ curl_setopt($fp, CURLOPT_HEADER, 1);
+ curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
+ curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
+ curl_setopt($fp, CURLOPT_REFERER, $url);
+ curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
+ curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
+ if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
+ {
+ curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
+ }
+
+ $this->headers = curl_exec($fp);
+ if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
+ {
+ curl_setopt($fp, CURLOPT_ENCODING, 'none');
+ $this->headers = curl_exec($fp);
+ }
+ if (curl_errno($fp))
+ {
+ $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
+ $this->success = false;
+ }
+ else
+ {
+ $info = curl_getinfo($fp);
+ curl_close($fp);
+ $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
+ $this->headers = array_pop($this->headers);
+ $parser = new SimplePie_HTTP_Parser($this->headers);
+ if ($parser->parse())
+ {
+ $this->headers = $parser->headers;
+ $this->body = $parser->body;
+ $this->status_code = $parser->status_code;
+ if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+ {
+ $this->redirects++;
+ $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+ return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
+ $url_parts = parse_url($url);
+ $socket_host = $url_parts['host'];
+ if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
+ {
+ $socket_host = "ssl://$url_parts[host]";
+ $url_parts['port'] = 443;
+ }
+ if (!isset($url_parts['port']))
+ {
+ $url_parts['port'] = 80;
+ }
+ $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
+ if (!$fp)
+ {
+ $this->error = 'fsockopen error: ' . $errstr;
+ $this->success = false;
+ }
+ else
+ {
+ stream_set_timeout($fp, $timeout);
+ if (isset($url_parts['path']))
+ {
+ if (isset($url_parts['query']))
+ {
+ $get = "$url_parts[path]?$url_parts[query]";
+ }
+ else
+ {
+ $get = $url_parts['path'];
+ }
+ }
+ else
+ {
+ $get = '/';
+ }
+ $out = "GET $get HTTP/1.1\r\n";
+ $out .= "Host: $url_parts[host]\r\n";
+ $out .= "User-Agent: $useragent\r\n";
+ if (extension_loaded('zlib'))
+ {
+ $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
+ }
+
+ if (isset($url_parts['user']) && isset($url_parts['pass']))
+ {
+ $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
+ }
+ foreach ($headers as $key => $value)
+ {
+ $out .= "$key: $value\r\n";
+ }
+ $out .= "Connection: Close\r\n\r\n";
+ fwrite($fp, $out);
+
+ $info = stream_get_meta_data($fp);
+
+ $this->headers = '';
+ while (!$info['eof'] && !$info['timed_out'])
+ {
+ $this->headers .= fread($fp, 1160);
+ $info = stream_get_meta_data($fp);
+ }
+ if (!$info['timed_out'])
+ {
+ $parser = new SimplePie_HTTP_Parser($this->headers);
+ if ($parser->parse())
+ {
+ $this->headers = $parser->headers;
+ $this->body = $parser->body;
+ $this->status_code = $parser->status_code;
+ if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+ {
+ $this->redirects++;
+ $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+ return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ }
+ if (isset($this->headers['content-encoding']))
+ {
+ // Hey, we act dumb elsewhere, so let's do that here too
+ switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
+ {
+ case 'gzip':
+ case 'x-gzip':
+ $decoder = new SimplePie_gzdecode($this->body);
+ if (!$decoder->parse())
+ {
+ $this->error = 'Unable to decode HTTP "gzip" stream';
+ $this->success = false;
+ }
+ else
+ {
+ $this->body = $decoder->data;
+ }
+ break;
+
+ case 'deflate':
+ if (($decompressed = gzinflate($this->body)) !== false)
+ {
+ $this->body = $decompressed;
+ }
+ else if (($decompressed = gzuncompress($this->body)) !== false)
+ {
+ $this->body = $decompressed;
+ }
+ else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
+ {
+ $this->body = $decompressed;
+ }
+ else
+ {
+ $this->error = 'Unable to decode HTTP "deflate" stream';
+ $this->success = false;
+ }
+ break;
+
+ default:
+ $this->error = 'Unknown content coding';
+ $this->success = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->error = 'fsocket timed out';
+ $this->success = false;
+ }
+ fclose($fp);
+ }
+ }
+ }
+ else
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
+ if (!$this->body = file_get_contents($url))
+ {
+ $this->error = 'file_get_contents could not read the file';
+ $this->success = false;
+ }
+ }
+ }
+}
+
+/**
+ * Decode 'gzip' encoded HTTP data
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ * @link http://www.gzip.org/format.txt
+ */
+class SimplePie_gzdecode
+{
+ /**
+ * Compressed data
+ *
+ * @access private
+ * @var string
+ * @see gzdecode::$data
+ */
+ var $compressed_data;
+
+ /**
+ * Size of compressed data
+ *
+ * @access private
+ * @var int
+ */
+ var $compressed_size;
+
+ /**
+ * Minimum size of a valid gzip string
+ *
+ * @access private
+ * @var int
+ */
+ var $min_compressed_size = 18;
+
+ /**
+ * Current position of pointer
+ *
+ * @access private
+ * @var int
+ */
+ var $position = 0;
+
+ /**
+ * Flags (FLG)
+ *
+ * @access private
+ * @var int
+ */
+ var $flags;
+
+ /**
+ * Uncompressed data
+ *
+ * @access public
+ * @see gzdecode::$compressed_data
+ * @var string
+ */
+ var $data;
+
+ /**
+ * Modified time
+ *
+ * @access public
+ * @var int
+ */
+ var $MTIME;
+
+ /**
+ * Extra Flags
+ *
+ * @access public
+ * @var int
+ */
+ var $XFL;
+
+ /**
+ * Operating System
+ *
+ * @access public
+ * @var int
+ */
+ var $OS;
+
+ /**
+ * Subfield ID 1
+ *
+ * @access public
+ * @see gzdecode::$extra_field
+ * @see gzdecode::$SI2
+ * @var string
+ */
+ var $SI1;
+
+ /**
+ * Subfield ID 2
+ *
+ * @access public
+ * @see gzdecode::$extra_field
+ * @see gzdecode::$SI1
+ * @var string
+ */
+ var $SI2;
+
+ /**
+ * Extra field content
+ *
+ * @access public
+ * @see gzdecode::$SI1
+ * @see gzdecode::$SI2
+ * @var string
+ */
+ var $extra_field;
+
+ /**
+ * Original filename
+ *
+ * @access public
+ * @var string
+ */
+ var $filename;
+
+ /**
+ * Human readable comment
+ *
+ * @access public
+ * @var string
+ */
+ var $comment;
+
+ /**
+ * Don't allow anything to be set
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ public function __set($name, $value)
+ {
+ trigger_error("Cannot write property $name", E_USER_ERROR);
+ }
+
+ /**
+ * Set the compressed string and related properties
+ *
+ * @param string $data
+ */
+ public function __construct($data)
+ {
+ $this->compressed_data = $data;
+ $this->compressed_size = strlen($data);
+ }
+
+ /**
+ * Decode the GZIP stream
+ *
+ * @return bool Successfulness
+ */
+ public function parse()
+ {
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Check ID1, ID2, and CM
+ if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
+ {
+ return false;
+ }
+
+ // Get the FLG (FLaGs)
+ $this->flags = ord($this->compressed_data[3]);
+
+ // FLG bits above (1 << 4) are reserved
+ if ($this->flags > 0x1F)
+ {
+ return false;
+ }
+
+ // Advance the pointer after the above
+ $this->position += 4;
+
+ // MTIME
+ $mtime = substr($this->compressed_data, $this->position, 4);
+ // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
+ if (current(unpack('S', "\x00\x01")) === 1)
+ {
+ $mtime = strrev($mtime);
+ }
+ $this->MTIME = current(unpack('l', $mtime));
+ $this->position += 4;
+
+ // Get the XFL (eXtra FLags)
+ $this->XFL = ord($this->compressed_data[$this->position++]);
+
+ // Get the OS (Operating System)
+ $this->OS = ord($this->compressed_data[$this->position++]);
+
+ // Parse the FEXTRA
+ if ($this->flags & 4)
+ {
+ // Read subfield IDs
+ $this->SI1 = $this->compressed_data[$this->position++];
+ $this->SI2 = $this->compressed_data[$this->position++];
+
+ // SI2 set to zero is reserved for future use
+ if ($this->SI2 === "\x00")
+ {
+ return false;
+ }
+
+ // Get the length of the extra field
+ $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
+ $this->position += 2;
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 4;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the extra field to the given data
+ $this->extra_field = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FNAME
+ if ($this->flags & 8)
+ {
+ // Get the length of the filename
+ $len = strcspn($this->compressed_data, "\x00", $this->position);
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 1;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the original filename to the given string
+ $this->filename = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len + 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FCOMMENT
+ if ($this->flags & 16)
+ {
+ // Get the length of the comment
+ $len = strcspn($this->compressed_data, "\x00", $this->position);
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 1;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the original comment to the given string
+ $this->comment = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len + 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FHCRC
+ if ($this->flags & 2)
+ {
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 2;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Read the CRC
+ $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
+
+ // Check the CRC matches
+ if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
+ {
+ $this->position += 2;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Decompress the actual data
+ if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
+ {
+ return false;
+ }
+ else
+ {
+ $this->position = $this->compressed_size - 8;
+ }
+
+ // Check CRC of data
+ $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
+ $this->position += 4;
+ /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
+ {
+ return false;
+ }*/
+
+ // Check ISIZE of data
+ $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
+ $this->position += 4;
+ if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
+ {
+ return false;
+ }
+
+ // Wow, against all odds, we've actually got a valid gzip string
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+/**
+ * HTTP Response Parser
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ */
+class SimplePie_HTTP_Parser
+{
+ /**
+ * HTTP Version
+ *
+ * @var float
+ */
+ public $http_version = 0.0;
+
+ /**
+ * Status code
+ *
+ * @var int
+ */
+ public $status_code = 0;
+
+ /**
+ * Reason phrase
+ *
+ * @var string
+ */
+ public $reason = '';
+
+ /**
+ * Key/value pairs of the headers
+ *
+ * @var array
+ */
+ public $headers = array();
+
+ /**
+ * Body of the response
+ *
+ * @var string
+ */
+ public $body = '';
+
+ /**
+ * Current state of the state machine
+ *
+ * @var string
+ */
+ protected $state = 'http_version';
+
+ /**
+ * Input data
+ *
+ * @var string
+ */
+ protected $data = '';
+
+ /**
+ * Input data length (to avoid calling strlen() everytime this is needed)
+ *
+ * @var int
+ */
+ protected $data_length = 0;
+
+ /**
+ * Current position of the pointer
+ *
+ * @var int
+ */
+ protected $position = 0;
+
+ /**
+ * Name of the hedaer currently being parsed
+ *
+ * @var string
+ */
+ protected $name = '';
+
+ /**
+ * Value of the hedaer currently being parsed
+ *
+ * @var string
+ */
+ protected $value = '';
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @param string $data Input data
+ */
+ public function __construct($data)
+ {
+ $this->data = $data;
+ $this->data_length = strlen($this->data);
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @return bool true on success, false on failure
+ */
+ public function parse()
+ {
+ while ($this->state && $this->state !== 'emit' && $this->has_data())
+ {
+ $state = $this->state;
+ $this->$state();
+ }
+ $this->data = '';
+ if ($this->state === 'emit' || $this->state === 'body')
+ {
+ return true;
+ }
+ else
+ {
+ $this->http_version = '';
+ $this->status_code = '';
+ $this->reason = '';
+ $this->headers = array();
+ $this->body = '';
+ return false;
+ }
+ }
+
+ /**
+ * Check whether there is data beyond the pointer
+ *
+ * @return bool true if there is further data, false if not
+ */
+ protected function has_data()
+ {
+ return (bool) ($this->position < $this->data_length);
+ }
+
+ /**
+ * See if the next character is LWS
+ *
+ * @return bool true if the next character is LWS, false if not
+ */
+ protected function is_linear_whitespace()
+ {
+ return (bool) ($this->data[$this->position] === "\x09"
+ || $this->data[$this->position] === "\x20"
+ || ($this->data[$this->position] === "\x0A"
+ && isset($this->data[$this->position + 1])
+ && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
+ }
+
+ /**
+ * Parse the HTTP version
+ */
+ protected function http_version()
+ {
+ if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
+ {
+ $len = strspn($this->data, '0123456789.', 5);
+ $this->http_version = substr($this->data, 5, $len);
+ $this->position += 5 + $len;
+ if (substr_count($this->http_version, '.') <= 1)
+ {
+ $this->http_version = (float) $this->http_version;
+ $this->position += strspn($this->data, "\x09\x20", $this->position);
+ $this->state = 'status';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse the status code
+ */
+ protected function status()
+ {
+ if ($len = strspn($this->data, '0123456789', $this->position))
+ {
+ $this->status_code = (int) substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'reason';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse the reason phrase
+ */
+ protected function reason()
+ {
+ $len = strcspn($this->data, "\x0A", $this->position);
+ $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
+ $this->position += $len + 1;
+ $this->state = 'new_line';
+ }
+
+ /**
+ * Deal with a new line, shifting data around as needed
+ */
+ protected function new_line()
+ {
+ $this->value = trim($this->value, "\x0D\x20");
+ if ($this->name !== '' && $this->value !== '')
+ {
+ $this->name = strtolower($this->name);
+ // We should only use the last Content-Type header. c.f. issue #1
+ if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
+ {
+ $this->headers[$this->name] .= ', ' . $this->value;
+ }
+ else
+ {
+ $this->headers[$this->name] = $this->value;
+ }
+ }
+ $this->name = '';
+ $this->value = '';
+ if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
+ {
+ $this->position += 2;
+ $this->state = 'body';
+ }
+ elseif ($this->data[$this->position] === "\x0A")
+ {
+ $this->position++;
+ $this->state = 'body';
+ }
+ else
+ {
+ $this->state = 'name';
+ }
+ }
+
+ /**
+ * Parse a header name
+ */
+ protected function name()
+ {
+ $len = strcspn($this->data, "\x0A:", $this->position);
+ if (isset($this->data[$this->position + $len]))
+ {
+ if ($this->data[$this->position + $len] === "\x0A")
+ {
+ $this->position += $len;
+ $this->state = 'new_line';
+ }
+ else
+ {
+ $this->name = substr($this->data, $this->position, $len);
+ $this->position += $len + 1;
+ $this->state = 'value';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse LWS, replacing consecutive LWS characters with a single space
+ */
+ protected function linear_whitespace()
+ {
+ do
+ {
+ if (substr($this->data, $this->position, 2) === "\x0D\x0A")
+ {
+ $this->position += 2;
+ }
+ elseif ($this->data[$this->position] === "\x0A")
+ {
+ $this->position++;
+ }
+ $this->position += strspn($this->data, "\x09\x20", $this->position);
+ } while ($this->has_data() && $this->is_linear_whitespace());
+ $this->value .= "\x20";
+ }
+
+ /**
+ * See what state to move to while within non-quoted header values
+ */
+ protected function value()
+ {
+ if ($this->is_linear_whitespace())
+ {
+ $this->linear_whitespace();
+ }
+ else
+ {
+ switch ($this->data[$this->position])
+ {
+ case '"':
+ // Workaround for ETags: we have to include the quotes as
+ // part of the tag.
+ if (strtolower($this->name) === 'etag')
+ {
+ $this->value .= '"';
+ $this->position++;
+ $this->state = 'value_char';
+ break;
+ }
+ $this->position++;
+ $this->state = 'quote';
+ break;
+
+ case "\x0A":
+ $this->position++;
+ $this->state = 'new_line';
+ break;
+
+ default:
+ $this->state = 'value_char';
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse a header value while outside quotes
+ */
+ protected function value_char()
+ {
+ $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
+ $this->value .= substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'value';
+ }
+
+ /**
+ * See what state to move to while within quoted header values
+ */
+ protected function quote()
+ {
+ if ($this->is_linear_whitespace())
+ {
+ $this->linear_whitespace();
+ }
+ else
+ {
+ switch ($this->data[$this->position])
+ {
+ case '"':
+ $this->position++;
+ $this->state = 'value';
+ break;
+
+ case "\x0A":
+ $this->position++;
+ $this->state = 'new_line';
+ break;
+
+ case '\\':
+ $this->position++;
+ $this->state = 'quote_escaped';
+ break;
+
+ default:
+ $this->state = 'quote_char';
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse a header value while within quotes
+ */
+ protected function quote_char()
+ {
+ $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
+ $this->value .= substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'value';
+ }
+
+ /**
+ * Parse an escaped character within quotes
+ */
+ protected function quote_escaped()
+ {
+ $this->value .= $this->data[$this->position];
+ $this->position++;
+ $this->state = 'quote';
+ }
+
+ /**
+ * Parse the body
+ */
+ protected function body()
+ {
+ $this->body = substr($this->data, $this->position);
+ if (!empty($this->headers['transfer-encoding']))
+ {
+ unset($this->headers['transfer-encoding']);
+ $this->state = 'chunked';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+
+ /**
+ * Parsed a "Transfer-Encoding: chunked" body
+ */
+ protected function chunked()
+ {
+ if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
+ {
+ $this->state = 'emit';
+ return;
+ }
+
+ $decoded = '';
+ $encoded = $this->body;
+
+ while (true)
+ {
+ $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
+ if (!$is_chunked)
+ {
+ // Looks like it's not chunked after all
+ $this->state = 'emit';
+ return;
+ }
+
+ $length = hexdec(trim($matches[1]));
+ if ($length === 0)
+ {
+ // Ignore trailer headers
+ $this->state = 'emit';
+ $this->body = $decoded;
+ return;
+ }
+
+ $chunk_length = strlen($matches[0]);
+ $decoded .= $part = substr($encoded, $chunk_length, $length);
+ $encoded = substr($encoded, $chunk_length + $length + 2);
+
+ if (trim($encoded) === '0' || empty($encoded))
+ {
+ $this->state = 'emit';
+ $this->body = $decoded;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * IRI parser/serialiser/normaliser
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ * @author Geoffrey Sneddon
+ * @author Steve Minutillo
+ * @author Ryan McCue
+ * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ */
+class SimplePie_IRI
+{
+ /**
+ * Scheme
+ *
+ * @var string
+ */
+ protected $scheme = null;
+
+ /**
+ * User Information
+ *
+ * @var string
+ */
+ protected $iuserinfo = null;
+
+ /**
+ * ihost
+ *
+ * @var string
+ */
+ protected $ihost = null;
+
+ /**
+ * Port
+ *
+ * @var string
+ */
+ protected $port = null;
+
+ /**
+ * ipath
+ *
+ * @var string
+ */
+ protected $ipath = '';
+
+ /**
+ * iquery
+ *
+ * @var string
+ */
+ protected $iquery = null;
+
+ /**
+ * ifragment
+ *
+ * @var string
+ */
+ protected $ifragment = null;
+
+ /**
+ * Normalization database
+ *
+ * Each key is the scheme, each value is an array with each key as the IRI
+ * part and value as the default value for that part.
+ */
+ protected $normalization = array(
+ 'acap' => array(
+ 'port' => 674
+ ),
+ 'dict' => array(
+ 'port' => 2628
+ ),
+ 'file' => array(
+ 'ihost' => 'localhost'
+ ),
+ 'http' => array(
+ 'port' => 80,
+ 'ipath' => '/'
+ ),
+ 'https' => array(
+ 'port' => 443,
+ 'ipath' => '/'
+ ),
+ );
+
+ /**
+ * Return the entire IRI when you try and read the object as a string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->get_iri();
+ }
+
+ /**
+ * Overload __set() to provide access via properties
+ *
+ * @param string $name Property name
+ * @param mixed $value Property value
+ */
+ public function __set($name, $value)
+ {
+ if (method_exists($this, 'set_' . $name))
+ {
+ call_user_func(array($this, 'set_' . $name), $value);
+ }
+ elseif (
+ $name === 'iauthority'
+ || $name === 'iuserinfo'
+ || $name === 'ihost'
+ || $name === 'ipath'
+ || $name === 'iquery'
+ || $name === 'ifragment'
+ )
+ {
+ call_user_func(array($this, 'set_' . substr($name, 1)), $value);
+ }
+ }
+
+ /**
+ * Overload __get() to provide access via properties
+ *
+ * @param string $name Property name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ // isset() returns false for null, we don't want to do that
+ // Also why we use array_key_exists below instead of isset()
+ $props = get_object_vars($this);
+
+ if (
+ $name === 'iri' ||
+ $name === 'uri' ||
+ $name === 'iauthority' ||
+ $name === 'authority'
+ )
+ {
+ $return = $this->{"get_$name"}();
+ }
+ elseif (array_key_exists($name, $props))
+ {
+ $return = $this->$name;
+ }
+ // host -> ihost
+ elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
+ {
+ $name = $prop;
+ $return = $this->$prop;
+ }
+ // ischeme -> scheme
+ elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
+ {
+ $name = $prop;
+ $return = $this->$prop;
+ }
+ else
+ {
+ trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
+ $return = null;
+ }
+
+ if ($return === null && isset($this->normalization[$this->scheme][$name]))
+ {
+ return $this->normalization[$this->scheme][$name];
+ }
+ else
+ {
+ return $return;
+ }
+ }
+
+ /**
+ * Overload __isset() to provide access via properties
+ *
+ * @param string $name Property name
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ if (method_exists($this, 'get_' . $name) || isset($this->$name))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Overload __unset() to provide access via properties
+ *
+ * @param string $name Property name
+ */
+ public function __unset($name)
+ {
+ if (method_exists($this, 'set_' . $name))
+ {
+ call_user_func(array($this, 'set_' . $name), '');
+ }
+ }
+
+ /**
+ * Create a new IRI object, from a specified string
+ *
+ * @param string $iri
+ */
+ public function __construct($iri = null)
+ {
+ $this->set_iri($iri);
+ }
+
+ /**
+ * Create a new IRI object by resolving a relative IRI
+ *
+ * Returns false if $base is not absolute, otherwise an IRI.
+ *
+ * @param IRI|string $base (Absolute) Base IRI
+ * @param IRI|string $relative Relative IRI
+ * @return IRI|false
+ */
+ public static function absolutize($base, $relative)
+ {
+ if (!($relative instanceof SimplePie_IRI))
+ {
+ $relative = new SimplePie_IRI($relative);
+ }
+ if (!$relative->is_valid())
+ {
+ return false;
+ }
+ elseif ($relative->scheme !== null)
+ {
+ return clone $relative;
+ }
+ else
+ {
+ if (!($base instanceof SimplePie_IRI))
+ {
+ $base = new SimplePie_IRI($base);
+ }
+ if ($base->scheme !== null && $base->is_valid())
+ {
+ if ($relative->get_iri() !== '')
+ {
+ if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
+ {
+ $target = clone $relative;
+ $target->scheme = $base->scheme;
+ }
+ else
+ {
+ $target = new SimplePie_IRI;
+ $target->scheme = $base->scheme;
+ $target->iuserinfo = $base->iuserinfo;
+ $target->ihost = $base->ihost;
+ $target->port = $base->port;
+ if ($relative->ipath !== '')
+ {
+ if ($relative->ipath[0] === '/')
+ {
+ $target->ipath = $relative->ipath;
+ }
+ elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
+ {
+ $target->ipath = '/' . $relative->ipath;
+ }
+ elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
+ {
+ $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
+ }
+ else
+ {
+ $target->ipath = $relative->ipath;
+ }
+ $target->ipath = $target->remove_dot_segments($target->ipath);
+ $target->iquery = $relative->iquery;
+ }
+ else
+ {
+ $target->ipath = $base->ipath;
+ if ($relative->iquery !== null)
+ {
+ $target->iquery = $relative->iquery;
+ }
+ elseif ($base->iquery !== null)
+ {
+ $target->iquery = $base->iquery;
+ }
+ }
+ $target->ifragment = $relative->ifragment;
+ }
+ }
+ else
+ {
+ $target = clone $base;
+ $target->ifragment = null;
+ }
+ $target->scheme_normalization();
+ return $target;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Parse an IRI into scheme/authority/path/query/fragment segments
+ *
+ * @param string $iri
+ * @return array
+ */
+ protected function parse_iri($iri)
+ {
+ $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
+ if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
+ {
+ if ($match[1] === '')
+ {
+ $match['scheme'] = null;
+ }
+ if (!isset($match[3]) || $match[3] === '')
+ {
+ $match['authority'] = null;
+ }
+ if (!isset($match[5]))
+ {
+ $match['path'] = '';
+ }
+ if (!isset($match[6]) || $match[6] === '')
+ {
+ $match['query'] = null;
+ }
+ if (!isset($match[8]) || $match[8] === '')
+ {
+ $match['fragment'] = null;
+ }
+ return $match;
+ }
+ else
+ {
+ // This can occur when a paragraph is accidentally parsed as a URI
+ return false;
+ }
+ }
+
+ /**
+ * Remove dot segments from a path
+ *
+ * @param string $input
+ * @return string
+ */
+ protected function remove_dot_segments($input)
+ {
+ $output = '';
+ while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
+ {
+ // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
+ if (strpos($input, '../') === 0)
+ {
+ $input = substr($input, 3);
+ }
+ elseif (strpos($input, './') === 0)
+ {
+ $input = substr($input, 2);
+ }
+ // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
+ elseif (strpos($input, '/./') === 0)
+ {
+ $input = substr($input, 2);
+ }
+ elseif ($input === '/.')
+ {
+ $input = '/';
+ }
+ // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
+ elseif (strpos($input, '/../') === 0)
+ {
+ $input = substr($input, 3);
+ $output = substr_replace($output, '', strrpos($output, '/'));
+ }
+ elseif ($input === '/..')
+ {
+ $input = '/';
+ $output = substr_replace($output, '', strrpos($output, '/'));
+ }
+ // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
+ elseif ($input === '.' || $input === '..')
+ {
+ $input = '';
+ }
+ // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
+ elseif (($pos = strpos($input, '/', 1)) !== false)
+ {
+ $output .= substr($input, 0, $pos);
+ $input = substr_replace($input, '', 0, $pos);
+ }
+ else
+ {
+ $output .= $input;
+ $input = '';
+ }
+ }
+ return $output . $input;
+ }
+
+ /**
+ * Replace invalid character with percent encoding
+ *
+ * @param string $string Input string
+ * @param string $extra_chars Valid characters not in iunreserved or
+ * iprivate (this is ASCII-only)
+ * @param bool $iprivate Allow iprivate
+ * @return string
+ */
+ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
+ {
+ // Normalize as many pct-encoded sections as possible
+ $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
+
+ // Replace invalid percent characters
+ $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
+
+ // Add unreserved and % to $extra_chars (the latter is safe because all
+ // pct-encoded sections are now valid).
+ $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
+
+ // Now replace any bytes that aren't allowed with their pct-encoded versions
+ $position = 0;
+ $strlen = strlen($string);
+ while (($position += strspn($string, $extra_chars, $position)) < $strlen)
+ {
+ $value = ord($string[$position]);
+
+ // Start position
+ $start = $position;
+
+ // By default we are valid
+ $valid = true;
+
+ // No one byte sequences are valid due to the while.
+ // Two byte sequence:
+ if (($value & 0xE0) === 0xC0)
+ {
+ $character = ($value & 0x1F) << 6;
+ $length = 2;
+ $remaining = 1;
+ }
+ // Three byte sequence:
+ elseif (($value & 0xF0) === 0xE0)
+ {
+ $character = ($value & 0x0F) << 12;
+ $length = 3;
+ $remaining = 2;
+ }
+ // Four byte sequence:
+ elseif (($value & 0xF8) === 0xF0)
+ {
+ $character = ($value & 0x07) << 18;
+ $length = 4;
+ $remaining = 3;
+ }
+ // Invalid byte:
+ else
+ {
+ $valid = false;
+ $length = 1;
+ $remaining = 0;
+ }
+
+ if ($remaining)
+ {
+ if ($position + $length <= $strlen)
+ {
+ for ($position++; $remaining; $position++)
+ {
+ $value = ord($string[$position]);
+
+ // Check that the byte is valid, then add it to the character:
+ if (($value & 0xC0) === 0x80)
+ {
+ $character |= ($value & 0x3F) << (--$remaining * 6);
+ }
+ // If it is invalid, count the sequence as invalid and reprocess the current byte:
+ else
+ {
+ $valid = false;
+ $position--;
+ break;
+ }
+ }
+ }
+ else
+ {
+ $position = $strlen - 1;
+ $valid = false;
+ }
+ }
+
+ // Percent encode anything invalid or not in ucschar
+ if (
+ // Invalid sequences
+ !$valid
+ // Non-shortest form sequences are invalid
+ || $length > 1 && $character <= 0x7F
+ || $length > 2 && $character <= 0x7FF
+ || $length > 3 && $character <= 0xFFFF
+ // Outside of range of ucschar codepoints
+ // Noncharacters
+ || ($character & 0xFFFE) === 0xFFFE
+ || $character >= 0xFDD0 && $character <= 0xFDEF
+ || (
+ // Everything else not in ucschar
+ $character > 0xD7FF && $character < 0xF900
+ || $character < 0xA0
+ || $character > 0xEFFFD
+ )
+ && (
+ // Everything not in iprivate, if it applies
+ !$iprivate
+ || $character < 0xE000
+ || $character > 0x10FFFD
+ )
+ )
+ {
+ // If we were a character, pretend we weren't, but rather an error.
+ if ($valid)
+ $position--;
+
+ for ($j = $start; $j <= $position; $j++)
+ {
+ $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
+ $j += 2;
+ $position += 2;
+ $strlen += 2;
+ }
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Callback function for preg_replace_callback.
+ *
+ * Removes sequences of percent encoded bytes that represent UTF-8
+ * encoded characters in iunreserved
+ *
+ * @param array $match PCRE match
+ * @return string Replacement
+ */
+ protected function remove_iunreserved_percent_encoded($match)
+ {
+ // As we just have valid percent encoded sequences we can just explode
+ // and ignore the first member of the returned array (an empty string).
+ $bytes = explode('%', $match[0]);
+
+ // Initialize the new string (this is what will be returned) and that
+ // there are no bytes remaining in the current sequence (unsurprising
+ // at the first byte!).
+ $string = '';
+ $remaining = 0;
+
+ // Loop over each and every byte, and set $value to its value
+ for ($i = 1, $len = count($bytes); $i < $len; $i++)
+ {
+ $value = hexdec($bytes[$i]);
+
+ // If we're the first byte of sequence:
+ if (!$remaining)
+ {
+ // Start position
+ $start = $i;
+
+ // By default we are valid
+ $valid = true;
+
+ // One byte sequence:
+ if ($value <= 0x7F)
+ {
+ $character = $value;
+ $length = 1;
+ }
+ // Two byte sequence:
+ elseif (($value & 0xE0) === 0xC0)
+ {
+ $character = ($value & 0x1F) << 6;
+ $length = 2;
+ $remaining = 1;
+ }
+ // Three byte sequence:
+ elseif (($value & 0xF0) === 0xE0)
+ {
+ $character = ($value & 0x0F) << 12;
+ $length = 3;
+ $remaining = 2;
+ }
+ // Four byte sequence:
+ elseif (($value & 0xF8) === 0xF0)
+ {
+ $character = ($value & 0x07) << 18;
+ $length = 4;
+ $remaining = 3;
+ }
+ // Invalid byte:
+ else
+ {
+ $valid = false;
+ $remaining = 0;
+ }
+ }
+ // Continuation byte:
+ else
+ {
+ // Check that the byte is valid, then add it to the character:
+ if (($value & 0xC0) === 0x80)
+ {
+ $remaining--;
+ $character |= ($value & 0x3F) << ($remaining * 6);
+ }
+ // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
+ else
+ {
+ $valid = false;
+ $remaining = 0;
+ $i--;
+ }
+ }
+
+ // If we've reached the end of the current byte sequence, append it to Unicode::$data
+ if (!$remaining)
+ {
+ // Percent encode anything invalid or not in iunreserved
+ if (
+ // Invalid sequences
+ !$valid
+ // Non-shortest form sequences are invalid
+ || $length > 1 && $character <= 0x7F
+ || $length > 2 && $character <= 0x7FF
+ || $length > 3 && $character <= 0xFFFF
+ // Outside of range of iunreserved codepoints
+ || $character < 0x2D
+ || $character > 0xEFFFD
+ // Noncharacters
+ || ($character & 0xFFFE) === 0xFFFE
+ || $character >= 0xFDD0 && $character <= 0xFDEF
+ // Everything else not in iunreserved (this is all BMP)
+ || $character === 0x2F
+ || $character > 0x39 && $character < 0x41
+ || $character > 0x5A && $character < 0x61
+ || $character > 0x7A && $character < 0x7E
+ || $character > 0x7E && $character < 0xA0
+ || $character > 0xD7FF && $character < 0xF900
+ )
+ {
+ for ($j = $start; $j <= $i; $j++)
+ {
+ $string .= '%' . strtoupper($bytes[$j]);
+ }
+ }
+ else
+ {
+ for ($j = $start; $j <= $i; $j++)
+ {
+ $string .= chr(hexdec($bytes[$j]));
+ }
+ }
+ }
+ }
+
+ // If we have any bytes left over they are invalid (i.e., we are
+ // mid-way through a multi-byte sequence)
+ if ($remaining)
+ {
+ for ($j = $start; $j < $len; $j++)
+ {
+ $string .= '%' . strtoupper($bytes[$j]);
+ }
+ }
+
+ return $string;
+ }
+
+ protected function scheme_normalization()
+ {
+ if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
+ {
+ $this->iuserinfo = null;
+ }
+ if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
+ {
+ $this->ihost = null;
+ }
+ if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
+ {
+ $this->port = null;
+ }
+ if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
+ {
+ $this->ipath = '';
+ }
+ if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
+ {
+ $this->iquery = null;
+ }
+ if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
+ {
+ $this->ifragment = null;
+ }
+ }
+
+ /**
+ * Check if the object represents a valid IRI. This needs to be done on each
+ * call as some things change depending on another part of the IRI.
+ *
+ * @return bool
+ */
+ public function is_valid()
+ {
+ $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
+ if ($this->ipath !== '' &&
+ (
+ $isauthority && (
+ $this->ipath[0] !== '/' ||
+ substr($this->ipath, 0, 2) === '//'
+ ) ||
+ (
+ $this->scheme === null &&
+ !$isauthority &&
+ strpos($this->ipath, ':') !== false &&
+ (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
+ )
+ )
+ )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Set the entire IRI. Returns true on success, false on failure (if there
+ * are any invalid characters).
+ *
+ * @param string $iri
+ * @return bool
+ */
+ public function set_iri($iri)
+ {
+ static $cache;
+ if (!$cache)
+ {
+ $cache = array();
+ }
+
+ if ($iri === null)
+ {
+ return true;
+ }
+ elseif (isset($cache[$iri]))
+ {
+ list($this->scheme,
+ $this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $this->ipath,
+ $this->iquery,
+ $this->ifragment,
+ $return) = $cache[$iri];
+ return $return;
+ }
+ else
+ {
+ $parsed = $this->parse_iri((string) $iri);
+ if (!$parsed)
+ {
+ return false;
+ }
+
+ $return = $this->set_scheme($parsed['scheme'])
+ && $this->set_authority($parsed['authority'])
+ && $this->set_path($parsed['path'])
+ && $this->set_query($parsed['query'])
+ && $this->set_fragment($parsed['fragment']);
+
+ $cache[$iri] = array($this->scheme,
+ $this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $this->ipath,
+ $this->iquery,
+ $this->ifragment,
+ $return);
+ return $return;
+ }
+ }
+
+ /**
+ * Set the scheme. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $scheme
+ * @return bool
+ */
+ public function set_scheme($scheme)
+ {
+ if ($scheme === null)
+ {
+ $this->scheme = null;
+ }
+ elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
+ {
+ $this->scheme = null;
+ return false;
+ }
+ else
+ {
+ $this->scheme = strtolower($scheme);
+ }
+ return true;
+ }
+
+ /**
+ * Set the authority. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $authority
+ * @return bool
+ */
+ public function set_authority($authority)
+ {
+ static $cache;
+ if (!$cache)
+ $cache = array();
+
+ if ($authority === null)
+ {
+ $this->iuserinfo = null;
+ $this->ihost = null;
+ $this->port = null;
+ return true;
+ }
+ elseif (isset($cache[$authority]))
+ {
+ list($this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $return) = $cache[$authority];
+
+ return $return;
+ }
+ else
+ {
+ $remaining = $authority;
+ if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
+ {
+ $iuserinfo = substr($remaining, 0, $iuserinfo_end);
+ $remaining = substr($remaining, $iuserinfo_end + 1);
+ }
+ else
+ {
+ $iuserinfo = null;
+ }
+ if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
+ {
+ if (($port = substr($remaining, $port_start + 1)) === false)
+ {
+ $port = null;
+ }
+ $remaining = substr($remaining, 0, $port_start);
+ }
+ else
+ {
+ $port = null;
+ }
+
+ $return = $this->set_userinfo($iuserinfo) &&
+ $this->set_host($remaining) &&
+ $this->set_port($port);
+
+ $cache[$authority] = array($this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $return);
+
+ return $return;
+ }
+ }
+
+ /**
+ * Set the iuserinfo.
+ *
+ * @param string $iuserinfo
+ * @return bool
+ */
+ public function set_userinfo($iuserinfo)
+ {
+ if ($iuserinfo === null)
+ {
+ $this->iuserinfo = null;
+ }
+ else
+ {
+ $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
+ $this->scheme_normalization();
+ }
+
+ return true;
+ }
+
+ /**
+ * Set the ihost. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $ihost
+ * @return bool
+ */
+ public function set_host($ihost)
+ {
+ if ($ihost === null)
+ {
+ $this->ihost = null;
+ return true;
+ }
+ elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
+ {
+ if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
+ {
+ $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
+ }
+ else
+ {
+ $this->ihost = null;
+ return false;
+ }
+ }
+ else
+ {
+ $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
+
+ // Lowercase, but ignore pct-encoded sections (as they should
+ // remain uppercase). This must be done after the previous step
+ // as that can add unescaped characters.
+ $position = 0;
+ $strlen = strlen($ihost);
+ while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
+ {
+ if ($ihost[$position] === '%')
+ {
+ $position += 3;
+ }
+ else
+ {
+ $ihost[$position] = strtolower($ihost[$position]);
+ $position++;
+ }
+ }
+
+ $this->ihost = $ihost;
+ }
+
+ $this->scheme_normalization();
+
+ return true;
+ }
+
+ /**
+ * Set the port. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $port
+ * @return bool
+ */
+ public function set_port($port)
+ {
+ if ($port === null)
+ {
+ $this->port = null;
+ return true;
+ }
+ elseif (strspn($port, '0123456789') === strlen($port))
+ {
+ $this->port = (int) $port;
+ $this->scheme_normalization();
+ return true;
+ }
+ else
+ {
+ $this->port = null;
+ return false;
+ }
+ }
+
+ /**
+ * Set the ipath.
+ *
+ * @param string $ipath
+ * @return bool
+ */
+ public function set_path($ipath)
+ {
+ static $cache;
+ if (!$cache)
+ {
+ $cache = array();
+ }
+
+ $ipath = (string) $ipath;
+
+ if (isset($cache[$ipath]))
+ {
+ $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
+ }
+ else
+ {
+ $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
+ $removed = $this->remove_dot_segments($valid);
+
+ $cache[$ipath] = array($valid, $removed);
+ $this->ipath = ($this->scheme !== null) ? $removed : $valid;
+ }
+
+ $this->scheme_normalization();
+ return true;
+ }
+
+ /**
+ * Set the iquery.
+ *
+ * @param string $iquery
+ * @return bool
+ */
+ public function set_query($iquery)
+ {
+ if ($iquery === null)
+ {
+ $this->iquery = null;
+ }
+ else
+ {
+ $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
+ $this->scheme_normalization();
+ }
+ return true;
+ }
+
+ /**
+ * Set the ifragment.
+ *
+ * @param string $ifragment
+ * @return bool
+ */
+ public function set_fragment($ifragment)
+ {
+ if ($ifragment === null)
+ {
+ $this->ifragment = null;
+ }
+ else
+ {
+ $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
+ $this->scheme_normalization();
+ }
+ return true;
+ }
+
+ /**
+ * Convert an IRI to a URI (or parts thereof)
+ *
+ * @return string
+ */
+ public function to_uri($string)
+ {
+ static $non_ascii;
+ if (!$non_ascii)
+ {
+ $non_ascii = implode('', range("\x80", "\xFF"));
+ }
+
+ $position = 0;
+ $strlen = strlen($string);
+ while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
+ {
+ $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
+ $position += 3;
+ $strlen += 2;
+ }
+
+ return $string;
+ }
+
+ /**
+ * Get the complete IRI
+ *
+ * @return string
+ */
+ public function get_iri()
+ {
+ if (!$this->is_valid())
+ {
+ return false;
+ }
+
+ $iri = '';
+ if ($this->scheme !== null)
+ {
+ $iri .= $this->scheme . ':';
+ }
+ if (($iauthority = $this->get_iauthority()) !== null)
+ {
+ $iri .= '//' . $iauthority;
+ }
+ if ($this->ipath !== '')
+ {
+ $iri .= $this->ipath;
+ }
+ elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
+ {
+ $iri .= $this->normalization[$this->scheme]['ipath'];
+ }
+ if ($this->iquery !== null)
+ {
+ $iri .= '?' . $this->iquery;
+ }
+ if ($this->ifragment !== null)
+ {
+ $iri .= '#' . $this->ifragment;
+ }
+
+ return $iri;
+ }
+
+ /**
+ * Get the complete URI
+ *
+ * @return string
+ */
+ public function get_uri()
+ {
+ return $this->to_uri($this->get_iri());
+ }
+
+ /**
+ * Get the complete iauthority
+ *
+ * @return string
+ */
+ protected function get_iauthority()
+ {
+ if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
+ {
+ $iauthority = '';
+ if ($this->iuserinfo !== null)
+ {
+ $iauthority .= $this->iuserinfo . '@';
+ }
+ if ($this->ihost !== null)
+ {
+ $iauthority .= $this->ihost;
+ }
+ if ($this->port !== null)
+ {
+ $iauthority .= ':' . $this->port;
+ }
+ return $iauthority;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the complete authority
+ *
+ * @return string
+ */
+ protected function get_authority()
+ {
+ $iauthority = $this->get_iauthority();
+ if (is_string($iauthority))
+ return $this->to_uri($iauthority);
+ else
+ return $iauthority;
+ }
+}
+
+/**
+ * Manages all item-related data
+ *
+ * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_item_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
class SimplePie_Item
{
+ /**
+ * Parent feed
+ *
+ * @access private
+ * @var SimplePie
+ */
var $feed;
+
+ /**
+ * Raw data
+ *
+ * @access private
+ * @var array
+ */
var $data = array();
- function SimplePie_Item($feed, $data)
+ /**
+ * Registry object
+ *
+ * @see set_registry
+ * @var SimplePie_Registry
+ */
+ protected $registry;
+
+ /**
+ * Create a new item object
+ *
+ * This is usually used by {@see SimplePie::get_items} and
+ * {@see SimplePie::get_item}. Avoid creating this manually.
+ *
+ * @param SimplePie $feed Parent feed
+ * @param array $data Raw data
+ */
+ public function __construct($feed, $data)
{
$this->feed = $feed;
$this->data = $data;
}
- function __toString()
+ /**
+ * Set the registry handler
+ *
+ * This is usually used by {@see SimplePie_Registry::create}
+ *
+ * @since 1.3
+ * @param SimplePie_Registry $registry
+ */
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ /**
+ * Get a string representation of the item
+ *
+ * @return string
+ */
+ public function __toString()
{
return md5(serialize($this->data));
}
@@ -3127,7 +9088,7 @@ class SimplePie_Item
/**
* Remove items that link back to this before destroying this object
*/
- function __destruct()
+ public function __destruct()
{
if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
{
@@ -3135,7 +9096,21 @@ class SimplePie_Item
}
}
- function get_item_tags($namespace, $tag)
+ /**
+ * Get data for an item-level element
+ *
+ * This method allows you to get access to ANY element/attribute that is a
+ * sub-element of the item/entry tag.
+ *
+ * See {@see SimplePie::get_feed_tags()} for a description of the return value
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
+ */
+ public function get_item_tags($namespace, $tag)
{
if (isset($this->data['child'][$namespace][$tag]))
{
@@ -3147,22 +9122,63 @@ class SimplePie_Item
}
}
- function get_base($element = array())
+ /**
+ * Get the base URL value from the parent feed
+ *
+ * Uses `<xml:base>`
+ *
+ * @param array $element
+ * @return string
+ */
+ public function get_base($element = array())
{
return $this->feed->get_base($element);
}
- function sanitize($data, $type, $base = '')
+ /**
+ * Sanitize feed data
+ *
+ * @access private
+ * @see SimplePie::sanitize()
+ * @param string $data Data to sanitize
+ * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
+ * @param string $base Base URL to resolve URLs against
+ * @return string Sanitized data
+ */
+ public function sanitize($data, $type, $base = '')
{
return $this->feed->sanitize($data, $type, $base);
}
- function get_feed()
+ /**
+ * Get the parent feed
+ *
+ * Note: this may not work as you think for multifeeds!
+ *
+ * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
+ * @since 1.0
+ * @return SimplePie
+ */
+ public function get_feed()
{
return $this->feed;
}
- function get_id($hash = false)
+ /**
+ * Get the unique identifier for the item
+ *
+ * This is usually used when writing code to check for new items in a feed.
+ *
+ * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
+ * for RDF. If none of these are supplied (or `$hash` is true), creates an
+ * MD5 hash based on the permalink and title. If either of those are not
+ * supplied, creates a hash based on the full feed data.
+ *
+ * @since Beta 2
+ * @param boolean $hash Should we force using a hash instead of the supplied ID?
+ * @return string
+ */
+ public function get_id($hash = false)
{
if (!$hash)
{
@@ -3186,6 +9202,10 @@ class SimplePie_Item
{
return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
+ elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
+ {
+ return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
elseif (($return = $this->get_permalink()) !== null)
{
return $return;
@@ -3205,17 +9225,25 @@ class SimplePie_Item
}
}
- function get_title()
+ /**
+ * Get the title of the item
+ *
+ * Uses `<atom:title>`, `<title>` or `<dc:title>`
+ *
+ * @since Beta 2 (previously called `get_item_title` since 0.8)
+ * @return string|null
+ */
+ public function get_title()
{
if (!isset($this->data['title']))
{
if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
{
- $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
{
- $this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
{
@@ -3245,15 +9273,30 @@ class SimplePie_Item
return $this->data['title'];
}
- function get_description($description_only = false)
+ /**
+ * Get the content for the item
+ *
+ * Prefers summaries over full content , but will return full content if a
+ * summary does not exist.
+ *
+ * To prefer full content instead, use {@see get_content}
+ *
+ * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
+ * `<itunes:subtitle>`
+ *
+ * @since 0.8
+ * @param boolean $description_only Should we avoid falling back to the content?
+ * @return string|null
+ */
+ public function get_description($description_only = false)
{
if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
{
@@ -3294,15 +9337,29 @@ class SimplePie_Item
}
}
- function get_content($content_only = false)
+ /**
+ * Get the content for the item
+ *
+ * Prefers full content over summaries, but will return a summary if full
+ * content does not exist.
+ *
+ * To prefer summaries instead, use {@see get_description}
+ *
+ * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
+ *
+ * @since 1.0
+ * @param boolean $content_only Should we avoid falling back to the description?
+ * @return string|null
+ */
+ public function get_content($content_only = false)
{
if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_content_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
{
@@ -3318,7 +9375,14 @@ class SimplePie_Item
}
}
- function get_category($key = 0)
+ /**
+ * Get a category for the item
+ *
+ * @since Beta 3 (previously called `get_categories()` since Beta 2)
+ * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Category|null
+ */
+ public function get_category($key = 0)
{
$categories = $this->get_categories();
if (isset($categories[$key]))
@@ -3331,7 +9395,15 @@ class SimplePie_Item
}
}
- function get_categories()
+ /**
+ * Get all categories for the item
+ *
+ * Uses `<atom:category>`, `<category>` or `<dc:subject>`
+ *
+ * @since Beta 3
+ * @return array|null List of {@see SimplePie_Category} objects
+ */
+ public function get_categories()
{
$categories = array();
@@ -3352,7 +9424,7 @@ class SimplePie_Item
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
}
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
{
@@ -3367,20 +9439,20 @@ class SimplePie_Item
{
$scheme = null;
}
- $categories[] = new $this->feed->category_class($term, $scheme, null);
+ $categories[] = $this->registry->create('Category', array($term, $scheme, null));
}
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
{
- $categories[] = new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
{
- $categories[] = new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
if (!empty($categories))
{
- return SimplePie_Misc::array_unique($categories);
+ return array_unique($categories);
}
else
{
@@ -3388,7 +9460,14 @@ class SimplePie_Item
}
}
- function get_author($key = 0)
+ /**
+ * Get an author for the item
+ *
+ * @since Beta 2
+ * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_author($key = 0)
{
$authors = $this->get_authors();
if (isset($authors[$key]))
@@ -3401,7 +9480,14 @@ class SimplePie_Item
}
}
- function get_contributor($key = 0)
+ /**
+ * Get a contributor for the item
+ *
+ * @since 1.1
+ * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_contributor($key = 0)
{
$contributors = $this->get_contributors();
if (isset($contributors[$key]))
@@ -3414,7 +9500,15 @@ class SimplePie_Item
}
}
- function get_contributors()
+ /**
+ * Get all contributors for the item
+ *
+ * Uses `<atom:contributor>`
+ *
+ * @since 1.1
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_contributors()
{
$contributors = array();
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
@@ -3436,7 +9530,7 @@ class SimplePie_Item
}
if ($name !== null || $email !== null || $uri !== null)
{
- $contributors[] = new $this->feed->author_class($name, $uri, $email);
+ $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
}
}
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
@@ -3458,13 +9552,13 @@ class SimplePie_Item
}
if ($name !== null || $email !== null || $url !== null)
{
- $contributors[] = new $this->feed->author_class($name, $url, $email);
+ $contributors[] = $this->registry->create('Author', array($name, $url, $email));
}
}
if (!empty($contributors))
{
- return SimplePie_Misc::array_unique($contributors);
+ return array_unique($contributors);
}
else
{
@@ -3472,7 +9566,15 @@ class SimplePie_Item
}
}
- function get_authors()
+ /**
+ * Get all authors for the item
+ *
+ * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
+ *
+ * @since Beta 2
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_authors()
{
$authors = array();
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
@@ -3494,7 +9596,7 @@ class SimplePie_Item
}
if ($name !== null || $email !== null || $uri !== null)
{
- $authors[] = new $this->feed->author_class($name, $uri, $email);
+ $authors[] = $this->registry->create('Author', array($name, $uri, $email));
}
}
if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
@@ -3516,29 +9618,29 @@ class SimplePie_Item
}
if ($name !== null || $email !== null || $url !== null)
{
- $authors[] = new $this->feed->author_class($name, $url, $email);
+ $authors[] = $this->registry->create('Author', array($name, $url, $email));
}
}
if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
{
- $authors[] = new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
}
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
{
- $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
{
- $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
{
- $authors[] = new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
}
if (!empty($authors))
{
- return SimplePie_Misc::array_unique($authors);
+ return array_unique($authors);
}
elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
{
@@ -3554,11 +9656,19 @@ class SimplePie_Item
}
}
- function get_copyright()
+ /**
+ * Get the copyright info for the item
+ *
+ * Uses `<atom:rights>` or `<dc:rights>`
+ *
+ * @since 1.1
+ * @return string
+ */
+ public function get_copyright()
{
if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
{
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
}
elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
{
@@ -3574,7 +9684,21 @@ class SimplePie_Item
}
}
- function get_date($date_format = 'j F Y, g:i a')
+ /**
+ * Get the posting date/time for the item
+ *
+ * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
+ * `<atom:modified>`, `<pubDate>` or `<dc:date>`
+ *
+ * Note: obeys PHP's timezone setting. To get a UTC date/time, use
+ * {@see get_gmdate}
+ *
+ * @since Beta 2 (previously called `get_item_date` since 0.8)
+ *
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
+ * @return int|string|null
+ */
+ public function get_date($date_format = 'j F Y, g:i a')
{
if (!isset($this->data['date']))
{
@@ -3613,7 +9737,7 @@ class SimplePie_Item
if (!empty($this->data['date']['raw']))
{
- $parser = SimplePie_Parse_Date::get();
+ $parser = $this->registry->call('Parse_Date', 'get');
$this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
}
else
@@ -3642,7 +9766,71 @@ class SimplePie_Item
}
}
- function get_local_date($date_format = '%c')
+ /**
+ * Get the update date/time for the item
+ *
+ * Uses `<atom:updated>`
+ *
+ * Note: obeys PHP's timezone setting. To get a UTC date/time, use
+ * {@see get_gmdate}
+ *
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
+ * @return int|string|null
+ */
+ public function get_updated_date($date_format = 'j F Y, g:i a')
+ {
+ if (!isset($this->data['updated']))
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
+ {
+ $this->data['updated']['raw'] = $return[0]['data'];
+ }
+
+ if (!empty($this->data['updated']['raw']))
+ {
+ $parser = $this->registry->call('Parse_Date', 'get');
+ $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
+ }
+ else
+ {
+ $this->data['updated'] = null;
+ }
+ }
+ if ($this->data['updated'])
+ {
+ $date_format = (string) $date_format;
+ switch ($date_format)
+ {
+ case '':
+ return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
+
+ case 'U':
+ return $this->data['updated']['parsed'];
+
+ default:
+ return date($date_format, $this->data['updated']['parsed']);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the localized posting date/time for the item
+ *
+ * Returns the date formatted in the localized language. To display in
+ * languages other than the server's default, you need to change the locale
+ * with {@link http://php.net/setlocale setlocale()}. The available
+ * localizations depend on which ones are installed on your web server.
+ *
+ * @since 1.0
+ *
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
+ * @return int|string|null
+ */
+ public function get_local_date($date_format = '%c')
{
if (!$date_format)
{
@@ -3658,7 +9846,53 @@ class SimplePie_Item
}
}
- function get_permalink()
+ /**
+ * Get the posting date/time for the item (UTC time)
+ *
+ * @see get_date
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
+ * @return int|string|null
+ */
+ public function get_gmdate($date_format = 'j F Y, g:i a')
+ {
+ $date = $this->get_date('U');
+ if ($date === null)
+ {
+ return null;
+ }
+
+ return gmdate($date_format, $date);
+ }
+
+ /**
+ * Get the update date/time for the item (UTC time)
+ *
+ * @see get_updated_date
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
+ * @return int|string|null
+ */
+ public function get_updated_gmdate($date_format = 'j F Y, g:i a')
+ {
+ $date = $this->get_updated_date('U');
+ if ($date === null)
+ {
+ return null;
+ }
+
+ return gmdate($date_format, $date);
+ }
+
+ /**
+ * Get the permalink for the item
+ *
+ * Returns the first link available with a relationship of "alternate".
+ * Identical to {@see get_link()} with key 0
+ *
+ * @see get_link
+ * @since 0.8
+ * @return string|null Permalink URL
+ */
+ public function get_permalink()
{
$link = $this->get_link();
$enclosure = $this->get_enclosure(0);
@@ -3676,7 +9910,15 @@ class SimplePie_Item
}
}
- function get_link($key = 0, $rel = 'alternate')
+ /**
+ * Get a single link for the item
+ *
+ * @since Beta 3
+ * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
+ * @param string $rel The relationship of the link to return
+ * @return string|null Link URL
+ */
+ public function get_link($key = 0, $rel = 'alternate')
{
$links = $this->get_links($rel);
if ($links[$key] !== null)
@@ -3689,7 +9931,16 @@ class SimplePie_Item
}
}
- function get_links($rel = 'alternate')
+ /**
+ * Get all links for the item
+ *
+ * Uses `<atom:link>`, `<link>` or `<guid>`
+ *
+ * @since Beta 2
+ * @param string $rel The relationship of links to return
+ * @return array|null Links found for the item (strings)
+ */
+ public function get_links($rel = 'alternate')
{
if (!isset($this->data['links']))
{
@@ -3734,7 +9985,7 @@ class SimplePie_Item
$keys = array_keys($this->data['links']);
foreach ($keys as $key)
{
- if (SimplePie_Misc::is_isegment_nz_nc($key))
+ if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
{
if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
{
@@ -3764,9 +10015,16 @@ class SimplePie_Item
}
/**
+ * Get an enclosure from the item
+ *
+ * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
+ *
+ * @since Beta 2
* @todo Add ability to prefer one type of content over another (in a media group).
+ * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Enclosure|null
*/
- function get_enclosure($key = 0, $prefer = null)
+ public function get_enclosure($key = 0, $prefer = null)
{
$enclosures = $this->get_enclosures();
if (isset($enclosures[$key]))
@@ -3780,16 +10038,20 @@ class SimplePie_Item
}
/**
- * Grabs all available enclosures (podcasts, etc.)
+ * Get all available enclosures (podcasts, etc.)
*
* Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
*
- * At this point, we're pretty much assuming that all enclosures for an item are the same content. Anything else is too complicated to properly support.
+ * At this point, we're pretty much assuming that all enclosures for an item
+ * are the same content. Anything else is too complicated to
+ * properly support.
*
+ * @since Beta 2
* @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
* @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
+ * @return array|null List of SimplePie_Enclosure items
*/
- function get_enclosures()
+ public function get_enclosures()
{
if (!isset($this->data['enclosures']))
{
@@ -3843,7 +10105,7 @@ class SimplePie_Item
{
$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $captions_parent[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
}
}
elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
@@ -3875,12 +10137,12 @@ class SimplePie_Item
{
$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $captions_parent[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
}
}
if (is_array($captions_parent))
{
- $captions_parent = array_values(SimplePie_Misc::array_unique($captions_parent));
+ $captions_parent = array_values(array_unique($captions_parent));
}
// CATEGORIES
@@ -3905,7 +10167,7 @@ class SimplePie_Item
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
}
foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
{
@@ -3928,7 +10190,7 @@ class SimplePie_Item
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
}
foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
{
@@ -3939,7 +10201,7 @@ class SimplePie_Item
{
$label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
{
@@ -3949,13 +10211,13 @@ class SimplePie_Item
{
$label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories_parent[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
}
}
}
if (is_array($categories_parent))
{
- $categories_parent = array_values(SimplePie_Misc::array_unique($categories_parent));
+ $categories_parent = array_values(array_unique($categories_parent));
}
// COPYRIGHT
@@ -3971,7 +10233,7 @@ class SimplePie_Item
{
$copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $copyrights_parent = new $this->feed->copyright_class($copyright_url, $copyright_label);
+ $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
}
elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
{
@@ -3985,7 +10247,7 @@ class SimplePie_Item
{
$copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $copyrights_parent = new $this->feed->copyright_class($copyright_url, $copyright_label);
+ $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
}
// CREDITS
@@ -4012,7 +10274,7 @@ class SimplePie_Item
{
$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $credits_parent[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
}
}
elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
@@ -4038,12 +10300,12 @@ class SimplePie_Item
{
$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $credits_parent[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
}
}
if (is_array($credits_parent))
{
- $credits_parent = array_values(SimplePie_Misc::array_unique($credits_parent));
+ $credits_parent = array_values(array_unique($credits_parent));
}
// DESCRIPTION
@@ -4135,7 +10397,7 @@ class SimplePie_Item
}
if (is_array($hashes_parent))
{
- $hashes_parent = array_values(SimplePie_Misc::array_unique($hashes_parent));
+ $hashes_parent = array_values(array_unique($hashes_parent));
}
// KEYWORDS
@@ -4189,7 +10451,7 @@ class SimplePie_Item
}
if (is_array($keywords_parent))
{
- $keywords_parent = array_values(SimplePie_Misc::array_unique($keywords_parent));
+ $keywords_parent = array_values(array_unique($keywords_parent));
}
// PLAYER
@@ -4227,7 +10489,7 @@ class SimplePie_Item
{
$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
}
}
elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
@@ -4240,7 +10502,7 @@ class SimplePie_Item
{
$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
}
}
elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
@@ -4261,7 +10523,7 @@ class SimplePie_Item
{
$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
}
}
elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
@@ -4274,12 +10536,12 @@ class SimplePie_Item
{
$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $ratings_parent[] = new $this->feed->rating_class($rating_scheme, $rating_value);
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
}
}
if (is_array($ratings_parent))
{
- $ratings_parent = array_values(SimplePie_Misc::array_unique($ratings_parent));
+ $ratings_parent = array_values(array_unique($ratings_parent));
}
// RESTRICTIONS
@@ -4302,7 +10564,7 @@ class SimplePie_Item
{
$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
}
}
elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
@@ -4316,7 +10578,7 @@ class SimplePie_Item
{
$restriction_relationship = 'deny';
}
- $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
}
}
elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
@@ -4338,7 +10600,7 @@ class SimplePie_Item
{
$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
}
}
elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
@@ -4352,12 +10614,16 @@ class SimplePie_Item
{
$restriction_relationship = 'deny';
}
- $restrictions_parent[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
}
}
if (is_array($restrictions_parent))
{
- $restrictions_parent = array_values(SimplePie_Misc::array_unique($restrictions_parent));
+ $restrictions_parent = array_values(array_unique($restrictions_parent));
+ }
+ else
+ {
+ $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
}
// THUMBNAILS
@@ -4558,11 +10824,11 @@ class SimplePie_Item
{
$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
}
if (is_array($captions))
{
- $captions = array_values(SimplePie_Misc::array_unique($captions));
+ $captions = array_values(array_unique($captions));
}
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
@@ -4594,11 +10860,11 @@ class SimplePie_Item
{
$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
}
if (is_array($captions))
{
- $captions = array_values(SimplePie_Misc::array_unique($captions));
+ $captions = array_values(array_unique($captions));
}
}
else
@@ -4630,7 +10896,7 @@ class SimplePie_Item
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
}
}
if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
@@ -4656,20 +10922,20 @@ class SimplePie_Item
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
}
}
if (is_array($categories) && is_array($categories_parent))
{
- $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
+ $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
}
elseif (is_array($categories))
{
- $categories = array_values(SimplePie_Misc::array_unique($categories));
+ $categories = array_values(array_unique($categories));
}
elseif (is_array($categories_parent))
{
- $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
+ $categories = array_values(array_unique($categories_parent));
}
// COPYRIGHTS
@@ -4685,7 +10951,7 @@ class SimplePie_Item
{
$copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label);
+ $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
{
@@ -4699,7 +10965,7 @@ class SimplePie_Item
{
$copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label);
+ $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
}
else
{
@@ -4730,11 +10996,11 @@ class SimplePie_Item
{
$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
}
if (is_array($credits))
{
- $credits = array_values(SimplePie_Misc::array_unique($credits));
+ $credits = array_values(array_unique($credits));
}
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
@@ -4760,11 +11026,11 @@ class SimplePie_Item
{
$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
}
if (is_array($credits))
{
- $credits = array_values(SimplePie_Misc::array_unique($credits));
+ $credits = array_values(array_unique($credits));
}
}
else
@@ -4809,7 +11075,7 @@ class SimplePie_Item
}
if (is_array($hashes))
{
- $hashes = array_values(SimplePie_Misc::array_unique($hashes));
+ $hashes = array_values(array_unique($hashes));
}
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
@@ -4834,7 +11100,7 @@ class SimplePie_Item
}
if (is_array($hashes))
{
- $hashes = array_values(SimplePie_Misc::array_unique($hashes));
+ $hashes = array_values(array_unique($hashes));
}
}
else
@@ -4856,7 +11122,7 @@ class SimplePie_Item
}
if (is_array($keywords))
{
- $keywords = array_values(SimplePie_Misc::array_unique($keywords));
+ $keywords = array_values(array_unique($keywords));
}
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
@@ -4872,7 +11138,7 @@ class SimplePie_Item
}
if (is_array($keywords))
{
- $keywords = array_values(SimplePie_Misc::array_unique($keywords));
+ $keywords = array_values(array_unique($keywords));
}
}
else
@@ -4913,11 +11179,11 @@ class SimplePie_Item
{
$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value);
+ $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
}
if (is_array($ratings))
{
- $ratings = array_values(SimplePie_Misc::array_unique($ratings));
+ $ratings = array_values(array_unique($ratings));
}
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
@@ -4938,11 +11204,11 @@ class SimplePie_Item
{
$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value);
+ $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
}
if (is_array($ratings))
{
- $ratings = array_values(SimplePie_Misc::array_unique($ratings));
+ $ratings = array_values(array_unique($ratings));
}
}
else
@@ -4970,11 +11236,11 @@ class SimplePie_Item
{
$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
}
if (is_array($restrictions))
{
- $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+ $restrictions = array_values(array_unique($restrictions));
}
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
@@ -4996,11 +11262,11 @@ class SimplePie_Item
{
$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
}
if (is_array($restrictions))
{
- $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+ $restrictions = array_values(array_unique($restrictions));
}
}
else
@@ -5017,7 +11283,7 @@ class SimplePie_Item
}
if (is_array($thumbnails))
{
- $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+ $thumbnails = array_values(array_unique($thumbnails));
}
}
elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
@@ -5028,7 +11294,7 @@ class SimplePie_Item
}
if (is_array($thumbnails))
{
- $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+ $thumbnails = array_values(array_unique($thumbnails));
}
}
else
@@ -5050,7 +11316,7 @@ class SimplePie_Item
$title = $title_parent;
}
- $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
}
}
}
@@ -5182,11 +11448,11 @@ class SimplePie_Item
{
$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $captions[] = new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+ $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
}
if (is_array($captions))
{
- $captions = array_values(SimplePie_Misc::array_unique($captions));
+ $captions = array_values(array_unique($captions));
}
}
else
@@ -5218,20 +11484,20 @@ class SimplePie_Item
{
$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $categories[] = new $this->feed->category_class($term, $scheme, $label);
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
}
}
if (is_array($categories) && is_array($categories_parent))
{
- $categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
+ $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
}
elseif (is_array($categories))
{
- $categories = array_values(SimplePie_Misc::array_unique($categories));
+ $categories = array_values(array_unique($categories));
}
elseif (is_array($categories_parent))
{
- $categories = array_values(SimplePie_Misc::array_unique($categories_parent));
+ $categories = array_values(array_unique($categories_parent));
}
else
{
@@ -5251,7 +11517,7 @@ class SimplePie_Item
{
$copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $copyrights = new $this->feed->copyright_class($copyright_url, $copyright_label);
+ $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
}
else
{
@@ -5282,11 +11548,11 @@ class SimplePie_Item
{
$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $credits[] = new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+ $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
}
if (is_array($credits))
{
- $credits = array_values(SimplePie_Misc::array_unique($credits));
+ $credits = array_values(array_unique($credits));
}
}
else
@@ -5327,7 +11593,7 @@ class SimplePie_Item
}
if (is_array($hashes))
{
- $hashes = array_values(SimplePie_Misc::array_unique($hashes));
+ $hashes = array_values(array_unique($hashes));
}
}
else
@@ -5349,7 +11615,7 @@ class SimplePie_Item
}
if (is_array($keywords))
{
- $keywords = array_values(SimplePie_Misc::array_unique($keywords));
+ $keywords = array_values(array_unique($keywords));
}
}
else
@@ -5386,11 +11652,11 @@ class SimplePie_Item
{
$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $ratings[] = new $this->feed->rating_class($rating_scheme, $rating_value);
+ $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
}
if (is_array($ratings))
{
- $ratings = array_values(SimplePie_Misc::array_unique($ratings));
+ $ratings = array_values(array_unique($ratings));
}
}
else
@@ -5418,11 +11684,11 @@ class SimplePie_Item
{
$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
}
- $restrictions[] = new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+ $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
}
if (is_array($restrictions))
{
- $restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+ $restrictions = array_values(array_unique($restrictions));
}
}
else
@@ -5439,7 +11705,7 @@ class SimplePie_Item
}
if (is_array($thumbnails))
{
- $thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+ $thumbnails = array_values(array_unique($thumbnails));
}
}
else
@@ -5457,7 +11723,7 @@ class SimplePie_Item
$title = $title_parent;
}
- $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
}
}
}
@@ -5493,7 +11759,7 @@ class SimplePie_Item
}
// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
- $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
}
}
@@ -5528,7 +11794,7 @@ class SimplePie_Item
}
// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
- $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
}
}
@@ -5563,17 +11829,17 @@ class SimplePie_Item
}
// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
- $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
}
}
if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
{
// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
- $this->data['enclosures'][] = new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
}
- $this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures']));
+ $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
}
if (!empty($this->data['enclosures']))
{
@@ -5585,7 +11851,19 @@ class SimplePie_Item
}
}
- function get_latitude()
+ /**
+ * Get the latitude coordinates for the item
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:lat>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_latitude()
{
if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
{
@@ -5601,7 +11879,19 @@ class SimplePie_Item
}
}
- function get_longitude()
+ /**
+ * Get the longitude coordinates for the item
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_longitude()
{
if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
{
@@ -5621,1282 +11911,186 @@ class SimplePie_Item
}
}
- function get_source()
- {
- if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
- {
- return new $this->feed->source_class($this, $return[0]);
- }
- else
- {
- return null;
- }
- }
-
/**
- * Creates the add_to_* methods' return data
+ * Get the `<atom:source>` for the item
*
- * @access private
- * @param string $item_url String to prefix to the item permalink
- * @param string $title_url String to prefix to the item title
- * (and suffix to the item permalink)
- * @return mixed URL if feed exists, false otherwise
+ * @since 1.1
+ * @return SimplePie_Source|null
*/
- function add_to_service($item_url, $title_url = null, $summary_url = null)
+ public function get_source()
{
- if ($this->get_permalink() !== null)
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
{
- $return = $item_url . rawurlencode($this->get_permalink());
- if ($title_url !== null && $this->get_title() !== null)
- {
- $return .= $title_url . rawurlencode($this->get_title());
- }
- if ($summary_url !== null && $this->get_description() !== null)
- {
- $return .= $summary_url . rawurlencode($this->get_description());
- }
- return $this->sanitize($return, SIMPLEPIE_CONSTRUCT_IRI);
+ return $this->registry->create('Source', array($this, $return[0]));
}
else
{
return null;
}
}
-
- function add_to_blinklist()
- {
- return $this->add_to_service('http://www.blinklist.com/index.php?Action=Blink/addblink.php&Description=&Url=', '&Title=');
- }
-
- function add_to_blogmarks()
- {
- return $this->add_to_service('http://blogmarks.net/my/new.php?mini=1&simple=1&url=', '&title=');
- }
-
- function add_to_delicious()
- {
- return $this->add_to_service('http://del.icio.us/post/?v=4&url=', '&title=');
- }
-
- function add_to_digg()
- {
- return $this->add_to_service('http://digg.com/submit?url=', '&title=', '&bodytext=');
- }
-
- function add_to_furl()
- {
- return $this->add_to_service('http://www.furl.net/storeIt.jsp?u=', '&t=');
- }
-
- function add_to_magnolia()
- {
- return $this->add_to_service('http://ma.gnolia.com/bookmarklet/add?url=', '&title=');
- }
-
- function add_to_myweb20()
- {
- return $this->add_to_service('http://myweb2.search.yahoo.com/myresults/bookmarklet?u=', '&t=');
- }
-
- function add_to_newsvine()
- {
- return $this->add_to_service('http://www.newsvine.com/_wine/save?u=', '&h=');
- }
-
- function add_to_reddit()
- {
- return $this->add_to_service('http://reddit.com/submit?url=', '&title=');
- }
-
- function add_to_segnalo()
- {
- return $this->add_to_service('http://segnalo.com/post.html.php?url=', '&title=');
- }
-
- function add_to_simpy()
- {
- return $this->add_to_service('http://www.simpy.com/simpy/LinkAdd.do?href=', '&title=');
- }
-
- function add_to_spurl()
- {
- return $this->add_to_service('http://www.spurl.net/spurl.php?v=3&url=', '&title=');
- }
-
- function add_to_wists()
- {
- return $this->add_to_service('http://wists.com/r.php?c=&r=', '&title=');
- }
-
- function search_technorati()
- {
- return $this->add_to_service('http://www.technorati.com/search/');
- }
}
-class SimplePie_Source
+/**
+ * Used for feed auto-discovery
+ *
+ *
+ * This class can be overloaded with {@see SimplePie::set_locator_class()}
+ *
+ * @package SimplePie
+ */
+class SimplePie_Locator
{
- var $item;
- var $data = array();
-
- function SimplePie_Source($item, $data)
- {
- $this->item = $item;
- $this->data = $data;
- }
-
- function __toString()
- {
- return md5(serialize($this->data));
- }
-
- function get_source_tags($namespace, $tag)
- {
- if (isset($this->data['child'][$namespace][$tag]))
- {
- return $this->data['child'][$namespace][$tag];
- }
- else
- {
- return null;
- }
- }
-
- function get_base($element = array())
- {
- return $this->item->get_base($element);
- }
-
- function sanitize($data, $type, $base = '')
- {
- return $this->item->sanitize($data, $type, $base);
- }
+ var $useragent;
+ var $timeout;
+ var $file;
+ var $local = array();
+ var $elsewhere = array();
+ var $cached_entities = array();
+ var $http_base;
+ var $base;
+ var $base_location = 0;
+ var $checked_feeds = 0;
+ var $max_checked_feeds = 10;
+ protected $registry;
- function get_item()
+ public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
{
- return $this->item;
- }
+ $this->file = $file;
+ $this->useragent = $useragent;
+ $this->timeout = $timeout;
+ $this->max_checked_feeds = $max_checked_feeds;
- function get_title()
- {
- if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
- {
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
- {
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
+ if (class_exists('DOMDocument'))
{
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- else
- {
- return null;
- }
- }
+ $this->dom = new DOMDocument();
- function get_category($key = 0)
- {
- $categories = $this->get_categories();
- if (isset($categories[$key]))
- {
- return $categories[$key];
+ set_error_handler(array('SimplePie_Misc', 'silence_errors'));
+ $this->dom->loadHTML($this->file->body);
+ restore_error_handler();
}
else
{
- return null;
+ $this->dom = null;
}
}
- function get_categories()
+ public function set_registry(SimplePie_Registry $registry)
{
- $categories = array();
-
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
- {
- $term = null;
- $scheme = null;
- $label = null;
- if (isset($category['attribs']['']['term']))
- {
- $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if (isset($category['attribs']['']['scheme']))
- {
- $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if (isset($category['attribs']['']['label']))
- {
- $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- $categories[] = new $this->item->feed->category_class($term, $scheme, $label);
- }
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
- {
- // This is really the label, but keep this as the term also for BC.
- // Label will also work on retrieving because that falls back to term.
- $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- if (isset($category['attribs']['']['domain']))
- {
- $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- else
- {
- $scheme = null;
- }
- $categories[] = new $this->item->feed->category_class($term, $scheme, null);
- }
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
- {
- $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
- }
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
- {
- $categories[] = new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
- }
-
- if (!empty($categories))
- {
- return SimplePie_Misc::array_unique($categories);
- }
- else
- {
- return null;
- }
+ $this->registry = $registry;
}
- function get_author($key = 0)
+ public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
{
- $authors = $this->get_authors();
- if (isset($authors[$key]))
- {
- return $authors[$key];
- }
- else
+ if ($this->is_feed($this->file))
{
- return null;
+ return $this->file;
}
- }
- function get_authors()
- {
- $authors = array();
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
- {
- $name = null;
- $uri = null;
- $email = null;
- if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
- {
- $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
- {
- $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
- }
- if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
- {
- $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if ($name !== null || $email !== null || $uri !== null)
- {
- $authors[] = new $this->item->feed->author_class($name, $uri, $email);
- }
- }
- if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
{
- $name = null;
- $url = null;
- $email = null;
- if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
- {
- $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
- {
- $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
- }
- if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
- {
- $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if ($name !== null || $email !== null || $url !== null)
+ $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
+ if ($sniffer->get_type() !== 'text/html')
{
- $authors[] = new $this->item->feed->author_class($name, $url, $email);
+ return null;
}
}
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
- {
- $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
- }
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
- {
- $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
- }
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
- {
- $authors[] = new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
- }
- if (!empty($authors))
- {
- return SimplePie_Misc::array_unique($authors);
- }
- else
+ if ($type & ~SIMPLEPIE_LOCATOR_NONE)
{
- return null;
+ $this->get_base();
}
- }
- function get_contributor($key = 0)
- {
- $contributors = $this->get_contributors();
- if (isset($contributors[$key]))
- {
- return $contributors[$key];
- }
- else
+ if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
{
- return null;
+ return $working[0];
}
- }
- function get_contributors()
- {
- $contributors = array();
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
- {
- $name = null;
- $uri = null;
- $email = null;
- if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
- {
- $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
- {
- $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
- }
- if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
- {
- $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if ($name !== null || $email !== null || $uri !== null)
- {
- $contributors[] = new $this->item->feed->author_class($name, $uri, $email);
- }
- }
- foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
{
- $name = null;
- $url = null;
- $email = null;
- if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
- {
- $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
- {
- $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
- }
- if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
- {
- $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- if ($name !== null || $email !== null || $url !== null)
+ if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
{
- $contributors[] = new $this->item->feed->author_class($name, $url, $email);
+ return $working;
}
- }
-
- if (!empty($contributors))
- {
- return SimplePie_Misc::array_unique($contributors);
- }
- else
- {
- return null;
- }
- }
-
- function get_link($key = 0, $rel = 'alternate')
- {
- $links = $this->get_links($rel);
- if (isset($links[$key]))
- {
- return $links[$key];
- }
- else
- {
- return null;
- }
- }
- /**
- * Added for parity between the parent-level and the item/entry-level.
- */
- function get_permalink()
- {
- return $this->get_link(0);
- }
-
- function get_links($rel = 'alternate')
- {
- if (!isset($this->data['links']))
- {
- $this->data['links'] = array();
- if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+ if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
{
- foreach ($links as $link)
- {
- if (isset($link['attribs']['']['href']))
- {
- $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
- $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
- }
- }
+ return $working;
}
- if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
- {
- foreach ($links as $link)
- {
- if (isset($link['attribs']['']['href']))
- {
- $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
- $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
- }
- }
- }
- if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
- {
- $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
- }
- if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
- {
- $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
- }
- if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
+ if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
{
- $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ return $working;
}
- $keys = array_keys($this->data['links']);
- foreach ($keys as $key)
+ if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
{
- if (SimplePie_Misc::is_isegment_nz_nc($key))
- {
- if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
- {
- $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
- $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
- }
- else
- {
- $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
- }
- }
- elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
- {
- $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
- }
- $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ return $working;
}
}
-
- if (isset($this->data['links'][$rel]))
- {
- return $this->data['links'][$rel];
- }
- else
- {
- return null;
- }
- }
-
- function get_description()
- {
- if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
- {
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
- {
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
- }
- else
- {
- return null;
- }
- }
-
- function get_copyright()
- {
- if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
- {
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
- {
- return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- else
- {
- return null;
- }
- }
-
- function get_language()
- {
- if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- elseif (isset($this->data['xml_lang']))
- {
- return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
- }
- else
- {
- return null;
- }
- }
-
- function get_latitude()
- {
- if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
- {
- return (float) $return[0]['data'];
- }
- elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
- {
- return (float) $match[1];
- }
- else
- {
- return null;
- }
- }
-
- function get_longitude()
- {
- if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
- {
- return (float) $return[0]['data'];
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
- {
- return (float) $return[0]['data'];
- }
- elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
- {
- return (float) $match[2];
- }
- else
- {
- return null;
- }
- }
-
- function get_image_url()
- {
- if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
- {
- return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
- }
- elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
- {
- return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
- }
- else
- {
- return null;
- }
- }
-}
-
-class SimplePie_Author
-{
- var $name;
- var $link;
- var $email;
-
- // Constructor, used to input the data
- function SimplePie_Author($name = null, $link = null, $email = null)
- {
- $this->name = $name;
- $this->link = $link;
- $this->email = $email;
- }
-
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
- }
-
- function get_name()
- {
- if ($this->name !== null)
- {
- return $this->name;
- }
- else
- {
- return null;
- }
- }
-
- function get_link()
- {
- if ($this->link !== null)
- {
- return $this->link;
- }
- else
- {
- return null;
- }
- }
-
- function get_email()
- {
- if ($this->email !== null)
- {
- return $this->email;
- }
- else
- {
- return null;
- }
- }
-}
-
-class SimplePie_Category
-{
- var $term;
- var $scheme;
- var $label;
-
- // Constructor, used to input the data
- function SimplePie_Category($term = null, $scheme = null, $label = null)
- {
- $this->term = $term;
- $this->scheme = $scheme;
- $this->label = $label;
- }
-
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
- }
-
- function get_term()
- {
- if ($this->term !== null)
- {
- return $this->term;
- }
- else
- {
- return null;
- }
- }
-
- function get_scheme()
- {
- if ($this->scheme !== null)
- {
- return $this->scheme;
- }
- else
- {
- return null;
- }
- }
-
- function get_label()
- {
- if ($this->label !== null)
- {
- return $this->label;
- }
- else
- {
- return $this->get_term();
- }
- }
-}
-
-class SimplePie_Enclosure
-{
- var $bitrate;
- var $captions;
- var $categories;
- var $channels;
- var $copyright;
- var $credits;
- var $description;
- var $duration;
- var $expression;
- var $framerate;
- var $handler;
- var $hashes;
- var $height;
- var $javascript;
- var $keywords;
- var $lang;
- var $length;
- var $link;
- var $medium;
- var $player;
- var $ratings;
- var $restrictions;
- var $samplingrate;
- var $thumbnails;
- var $title;
- var $type;
- var $width;
-
- // Constructor, used to input the data
- function SimplePie_Enclosure($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
- {
- $this->bitrate = $bitrate;
- $this->captions = $captions;
- $this->categories = $categories;
- $this->channels = $channels;
- $this->copyright = $copyright;
- $this->credits = $credits;
- $this->description = $description;
- $this->duration = $duration;
- $this->expression = $expression;
- $this->framerate = $framerate;
- $this->hashes = $hashes;
- $this->height = $height;
- $this->javascript = $javascript;
- $this->keywords = $keywords;
- $this->lang = $lang;
- $this->length = $length;
- $this->link = $link;
- $this->medium = $medium;
- $this->player = $player;
- $this->ratings = $ratings;
- $this->restrictions = $restrictions;
- $this->samplingrate = $samplingrate;
- $this->thumbnails = $thumbnails;
- $this->title = $title;
- $this->type = $type;
- $this->width = $width;
- if (class_exists('idna_convert'))
- {
- $idn = new idna_convert;
- $parsed = SimplePie_Misc::parse_url($link);
- $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
- }
- $this->handler = $this->get_handler(); // Needs to load last
- }
-
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
- }
-
- function get_bitrate()
- {
- if ($this->bitrate !== null)
- {
- return $this->bitrate;
- }
- else
- {
- return null;
- }
- }
-
- function get_caption($key = 0)
- {
- $captions = $this->get_captions();
- if (isset($captions[$key]))
- {
- return $captions[$key];
- }
- else
- {
- return null;
- }
- }
-
- function get_captions()
- {
- if ($this->captions !== null)
- {
- return $this->captions;
- }
- else
- {
- return null;
- }
- }
-
- function get_category($key = 0)
- {
- $categories = $this->get_categories();
- if (isset($categories[$key]))
- {
- return $categories[$key];
- }
- else
- {
- return null;
- }
- }
-
- function get_categories()
- {
- if ($this->categories !== null)
- {
- return $this->categories;
- }
- else
- {
- return null;
- }
- }
-
- function get_channels()
- {
- if ($this->channels !== null)
- {
- return $this->channels;
- }
- else
- {
- return null;
- }
- }
-
- function get_copyright()
- {
- if ($this->copyright !== null)
- {
- return $this->copyright;
- }
- else
- {
- return null;
- }
- }
-
- function get_credit($key = 0)
- {
- $credits = $this->get_credits();
- if (isset($credits[$key]))
- {
- return $credits[$key];
- }
- else
- {
- return null;
- }
- }
-
- function get_credits()
- {
- if ($this->credits !== null)
- {
- return $this->credits;
- }
- else
- {
- return null;
- }
- }
-
- function get_description()
- {
- if ($this->description !== null)
- {
- return $this->description;
- }
- else
- {
- return null;
- }
+ return null;
}
- function get_duration($convert = false)
+ public function is_feed($file)
{
- if ($this->duration !== null)
+ if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
{
- if ($convert)
+ $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
+ $sniffed = $sniffer->get_type();
+ if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
{
- $time = SimplePie_Misc::time_hms($this->duration);
- return $time;
+ return true;
}
else
{
- return $this->duration;
- }
- }
- else
- {
- return null;
- }
- }
-
- function get_expression()
- {
- if ($this->expression !== null)
- {
- return $this->expression;
- }
- else
- {
- return 'full';
- }
- }
-
- function get_extension()
- {
- if ($this->link !== null)
- {
- $url = SimplePie_Misc::parse_url($this->link);
- if ($url['path'] !== '')
- {
- return pathinfo($url['path'], PATHINFO_EXTENSION);
+ return false;
}
}
- return null;
- }
-
- function get_framerate()
- {
- if ($this->framerate !== null)
- {
- return $this->framerate;
- }
- else
- {
- return null;
- }
- }
-
- function get_handler()
- {
- return $this->get_real_type(true);
- }
-
- function get_hash($key = 0)
- {
- $hashes = $this->get_hashes();
- if (isset($hashes[$key]))
- {
- return $hashes[$key];
- }
- else
- {
- return null;
- }
- }
-
- function get_hashes()
- {
- if ($this->hashes !== null)
- {
- return $this->hashes;
- }
- else
- {
- return null;
- }
- }
-
- function get_height()
- {
- if ($this->height !== null)
- {
- return $this->height;
- }
- else
- {
- return null;
- }
- }
-
- function get_language()
- {
- if ($this->lang !== null)
- {
- return $this->lang;
- }
- else
- {
- return null;
- }
- }
-
- function get_keyword($key = 0)
- {
- $keywords = $this->get_keywords();
- if (isset($keywords[$key]))
- {
- return $keywords[$key];
- }
- else
- {
- return null;
- }
- }
-
- function get_keywords()
- {
- if ($this->keywords !== null)
- {
- return $this->keywords;
- }
- else
- {
- return null;
- }
- }
-
- function get_length()
- {
- if ($this->length !== null)
- {
- return $this->length;
- }
- else
- {
- return null;
- }
- }
-
- function get_link()
- {
- if ($this->link !== null)
- {
- return urldecode($this->link);
- }
- else
- {
- return null;
- }
- }
-
- function get_medium()
- {
- if ($this->medium !== null)
- {
- return $this->medium;
- }
- else
- {
- return null;
- }
- }
-
- function get_player()
- {
- if ($this->player !== null)
- {
- return $this->player;
- }
- else
- {
- return null;
- }
- }
-
- function get_rating($key = 0)
- {
- $ratings = $this->get_ratings();
- if (isset($ratings[$key]))
- {
- return $ratings[$key];
- }
- else
- {
- return null;
- }
- }
-
- function get_ratings()
- {
- if ($this->ratings !== null)
- {
- return $this->ratings;
- }
- else
- {
- return null;
- }
- }
-
- function get_restriction($key = 0)
- {
- $restrictions = $this->get_restrictions();
- if (isset($restrictions[$key]))
- {
- return $restrictions[$key];
- }
- else
- {
- return null;
- }
- }
-
- function get_restrictions()
- {
- if ($this->restrictions !== null)
- {
- return $this->restrictions;
- }
- else
- {
- return null;
- }
- }
-
- function get_sampling_rate()
- {
- if ($this->samplingrate !== null)
- {
- return $this->samplingrate;
- }
- else
- {
- return null;
- }
- }
-
- function get_size()
- {
- $length = $this->get_length();
- if ($length !== null)
- {
- return round($length/1048576, 2);
- }
- else
- {
- return null;
- }
- }
-
- function get_thumbnail($key = 0)
- {
- $thumbnails = $this->get_thumbnails();
- if (isset($thumbnails[$key]))
+ elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
{
- return $thumbnails[$key];
+ return true;
}
else
{
- return null;
+ return false;
}
}
- function get_thumbnails()
+ public function get_base()
{
- if ($this->thumbnails !== null)
+ if ($this->dom === null)
{
- return $this->thumbnails;
+ throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
}
- else
+ $this->http_base = $this->file->url;
+ $this->base = $this->http_base;
+ $elements = $this->dom->getElementsByTagName('base');
+ foreach ($elements as $element)
{
- return null;
+ if ($element->hasAttribute('href'))
+ {
+ $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
+ if ($base === false)
+ {
+ continue;
+ }
+ $this->base = $base;
+ $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
+ break;
+ }
}
}
- function get_title()
+ public function autodiscovery()
{
- if ($this->title !== null)
- {
- return $this->title;
- }
- else
- {
- return null;
- }
- }
+ $done = array();
+ $feeds = array();
+ $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
+ $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
+ $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
- function get_type()
- {
- if ($this->type !== null)
+ if (!empty($feeds))
{
- return $this->type;
+ return array_values($feeds);
}
else
{
@@ -6904,2186 +12098,174 @@ class SimplePie_Enclosure
}
}
- function get_width()
+ protected function search_elements_by_tag($name, &$done, $feeds)
{
- if ($this->width !== null)
+ if ($this->dom === null)
{
- return $this->width;
+ throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
}
- else
- {
- return null;
- }
- }
-
- function native_embed($options='')
- {
- return $this->embed($options, true);
- }
-
- /**
- * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
- */
- function embed($options = '', $native = false)
- {
- // Set up defaults
- $audio = '';
- $video = '';
- $alt = '';
- $altclass = '';
- $loop = 'false';
- $width = 'auto';
- $height = 'auto';
- $bgcolor = '#ffffff';
- $mediaplayer = '';
- $widescreen = false;
- $handler = $this->get_handler();
- $type = $this->get_real_type();
- // Process options and reassign values as necessary
- if (is_array($options))
- {
- extract($options);
- }
- else
+ $links = $this->dom->getElementsByTagName($name);
+ foreach ($links as $link)
{
- $options = explode(',', $options);
- foreach($options as $option)
+ if ($this->checked_feeds === $this->max_checked_feeds)
{
- $opt = explode(':', $option, 2);
- if (isset($opt[0], $opt[1]))
- {
- $opt[0] = trim($opt[0]);
- $opt[1] = trim($opt[1]);
- switch ($opt[0])
- {
- case 'audio':
- $audio = $opt[1];
- break;
-
- case 'video':
- $video = $opt[1];
- break;
-
- case 'alt':
- $alt = $opt[1];
- break;
-
- case 'altclass':
- $altclass = $opt[1];
- break;
-
- case 'loop':
- $loop = $opt[1];
- break;
-
- case 'width':
- $width = $opt[1];
- break;
-
- case 'height':
- $height = $opt[1];
- break;
-
- case 'bgcolor':
- $bgcolor = $opt[1];
- break;
-
- case 'mediaplayer':
- $mediaplayer = $opt[1];
- break;
-
- case 'widescreen':
- $widescreen = $opt[1];
- break;
- }
- }
+ break;
}
- }
-
- $mime = explode('/', $type, 2);
- $mime = $mime[0];
-
- // Process values for 'auto'
- if ($width === 'auto')
- {
- if ($mime === 'video')
+ if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
{
- if ($height === 'auto')
+ $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
+ $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
+
+ if ($this->base_location < $line)
{
- $width = 480;
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
}
- elseif ($widescreen)
+ else
{
- $width = round((intval($height)/9)*16);
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
}
- else
+ if ($href === false)
{
- $width = round((intval($height)/3)*4);
+ continue;
}
- }
- else
- {
- $width = '100%';
- }
- }
- if ($height === 'auto')
- {
- if ($mime === 'audio')
- {
- $height = 0;
- }
- elseif ($mime === 'video')
- {
- if ($width === 'auto')
+ if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
{
- if ($widescreen)
- {
- $height = 270;
- }
- else
+ $this->checked_feeds++;
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
+ if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
{
- $height = 360;
+ $feeds[$href] = $feed;
}
}
- elseif ($widescreen)
- {
- $height = round((intval($width)/16)*9);
- }
- else
- {
- $height = round((intval($width)/4)*3);
- }
- }
- else
- {
- $height = 376;
- }
- }
- elseif ($mime === 'audio')
- {
- $height = 0;
- }
-
- // Set proper placeholder value
- if ($mime === 'audio')
- {
- $placeholder = $audio;
- }
- elseif ($mime === 'video')
- {
- $placeholder = $video;
- }
-
- $embed = '';
-
- // Make sure the JS library is included
- if (!$native)
- {
- static $javascript_outputted = null;
- if (!$javascript_outputted && $this->javascript)
- {
- $embed .= '<script type="text/javascript" src="?' . htmlspecialchars($this->javascript) . '"></script>';
- $javascript_outputted = true;
- }
- }
-
- // Odeo Feed MP3's
- if ($handler === 'odeo')
- {
- if ($native)
- {
- $embed .= '<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://adobe.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url=' . $this->get_link() . '"></embed>';
- }
- else
- {
- $embed .= '<script type="text/javascript">embed_odeo("' . $this->get_link() . '");</script>';
- }
- }
-
- // Flash
- elseif ($handler === 'flash')
- {
- if ($native)
- {
- $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
- }
- else
- {
- $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
- }
- }
-
- // Flash Media Player file types.
- // Preferred handler for MP3 file types.
- elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
- {
- $height += 20;
- if ($native)
- {
- $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
- }
- else
- {
- $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
- }
- }
-
- // QuickTime 7 file types. Need to test with QuickTime 6.
- // Only handle MP3's if the Flash Media Player is not present.
- elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
- {
- $height += 16;
- if ($native)
- {
- if ($placeholder !== '')
- {
- $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
- }
- else
- {
- $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
- }
- }
- else
- {
- $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
- }
- }
-
- // Windows Media
- elseif ($handler === 'wmedia')
- {
- $height += 45;
- if ($native)
- {
- $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
- }
- else
- {
- $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
- }
- }
-
- // Everything else
- else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
-
- return $embed;
- }
-
- function get_real_type($find_handler = false)
- {
- // If it's Odeo, let's get it out of the way.
- if (substr(strtolower($this->get_link()), 0, 15) === 'http://odeo.com')
- {
- return 'odeo';
- }
-
- // Mime-types by handler.
- $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
- $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
- $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
- $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
- $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
-
- if ($this->get_type() !== null)
- {
- $type = strtolower($this->type);
- }
- else
- {
- $type = null;
- }
-
- // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
- if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
- {
- switch (strtolower($this->get_extension()))
- {
- // Audio mime-types
- case 'aac':
- case 'adts':
- $type = 'audio/acc';
- break;
-
- case 'aif':
- case 'aifc':
- case 'aiff':
- case 'cdda':
- $type = 'audio/aiff';
- break;
-
- case 'bwf':
- $type = 'audio/wav';
- break;
-
- case 'kar':
- case 'mid':
- case 'midi':
- case 'smf':
- $type = 'audio/midi';
- break;
-
- case 'm4a':
- $type = 'audio/x-m4a';
- break;
-
- case 'mp3':
- case 'swa':
- $type = 'audio/mp3';
- break;
-
- case 'wav':
- $type = 'audio/wav';
- break;
-
- case 'wax':
- $type = 'audio/x-ms-wax';
- break;
-
- case 'wma':
- $type = 'audio/x-ms-wma';
- break;
-
- // Video mime-types
- case '3gp':
- case '3gpp':
- $type = 'video/3gpp';
- break;
-
- case '3g2':
- case '3gp2':
- $type = 'video/3gpp2';
- break;
-
- case 'asf':
- $type = 'video/x-ms-asf';
- break;
-
- case 'flv':
- $type = 'video/x-flv';
- break;
-
- case 'm1a':
- case 'm1s':
- case 'm1v':
- case 'm15':
- case 'm75':
- case 'mp2':
- case 'mpa':
- case 'mpeg':
- case 'mpg':
- case 'mpm':
- case 'mpv':
- $type = 'video/mpeg';
- break;
-
- case 'm4v':
- $type = 'video/x-m4v';
- break;
-
- case 'mov':
- case 'qt':
- $type = 'video/quicktime';
- break;
-
- case 'mp4':
- case 'mpg4':
- $type = 'video/mp4';
- break;
-
- case 'sdv':
- $type = 'video/sd-video';
- break;
-
- case 'wm':
- $type = 'video/x-ms-wm';
- break;
-
- case 'wmv':
- $type = 'video/x-ms-wmv';
- break;
-
- case 'wvx':
- $type = 'video/x-ms-wvx';
- break;
-
- // Flash mime-types
- case 'spl':
- $type = 'application/futuresplash';
- break;
-
- case 'swf':
- $type = 'application/x-shockwave-flash';
- break;
- }
- }
-
- if ($find_handler)
- {
- if (in_array($type, $types_flash))
- {
- return 'flash';
- }
- elseif (in_array($type, $types_fmedia))
- {
- return 'fmedia';
- }
- elseif (in_array($type, $types_quicktime))
- {
- return 'quicktime';
- }
- elseif (in_array($type, $types_wmedia))
- {
- return 'wmedia';
- }
- elseif (in_array($type, $types_mp3))
- {
- return 'mp3';
- }
- else
- {
- return null;
+ $done[] = $href;
}
}
- else
- {
- return $type;
- }
- }
-}
-
-class SimplePie_Caption
-{
- var $type;
- var $lang;
- var $startTime;
- var $endTime;
- var $text;
-
- // Constructor, used to input the data
- function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
- {
- $this->type = $type;
- $this->lang = $lang;
- $this->startTime = $startTime;
- $this->endTime = $endTime;
- $this->text = $text;
- }
-
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
- }
-
- function get_endtime()
- {
- if ($this->endTime !== null)
- {
- return $this->endTime;
- }
- else
- {
- return null;
- }
- }
-
- function get_language()
- {
- if ($this->lang !== null)
- {
- return $this->lang;
- }
- else
- {
- return null;
- }
- }
-
- function get_starttime()
- {
- if ($this->startTime !== null)
- {
- return $this->startTime;
- }
- else
- {
- return null;
- }
- }
-
- function get_text()
- {
- if ($this->text !== null)
- {
- return $this->text;
- }
- else
- {
- return null;
- }
- }
-
- function get_type()
- {
- if ($this->type !== null)
- {
- return $this->type;
- }
- else
- {
- return null;
- }
- }
-}
-
-class SimplePie_Credit
-{
- var $role;
- var $scheme;
- var $name;
-
- // Constructor, used to input the data
- function SimplePie_Credit($role = null, $scheme = null, $name = null)
- {
- $this->role = $role;
- $this->scheme = $scheme;
- $this->name = $name;
- }
-
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
- }
-
- function get_role()
- {
- if ($this->role !== null)
- {
- return $this->role;
- }
- else
- {
- return null;
- }
- }
-
- function get_scheme()
- {
- if ($this->scheme !== null)
- {
- return $this->scheme;
- }
- else
- {
- return null;
- }
- }
-
- function get_name()
- {
- if ($this->name !== null)
- {
- return $this->name;
- }
- else
- {
- return null;
- }
- }
-}
-
-class SimplePie_Copyright
-{
- var $url;
- var $label;
-
- // Constructor, used to input the data
- function SimplePie_Copyright($url = null, $label = null)
- {
- $this->url = $url;
- $this->label = $label;
- }
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
+ return $feeds;
}
- function get_url()
+ public function get_links()
{
- if ($this->url !== null)
+ if ($this->dom === null)
{
- return $this->url;
+ throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
}
- else
- {
- return null;
- }
- }
- function get_attribution()
- {
- if ($this->label !== null)
- {
- return $this->label;
- }
- else
- {
- return null;
- }
- }
-}
-
-class SimplePie_Rating
-{
- var $scheme;
- var $value;
-
- // Constructor, used to input the data
- function SimplePie_Rating($scheme = null, $value = null)
- {
- $this->scheme = $scheme;
- $this->value = $value;
- }
-
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
- }
-
- function get_scheme()
- {
- if ($this->scheme !== null)
- {
- return $this->scheme;
- }
- else
- {
- return null;
- }
- }
-
- function get_value()
- {
- if ($this->value !== null)
- {
- return $this->value;
- }
- else
- {
- return null;
- }
- }
-}
-
-class SimplePie_Restriction
-{
- var $relationship;
- var $type;
- var $value;
-
- // Constructor, used to input the data
- function SimplePie_Restriction($relationship = null, $type = null, $value = null)
- {
- $this->relationship = $relationship;
- $this->type = $type;
- $this->value = $value;
- }
-
- function __toString()
- {
- // There is no $this->data here
- return md5(serialize($this));
- }
-
- function get_relationship()
- {
- if ($this->relationship !== null)
- {
- return $this->relationship;
- }
- else
- {
- return null;
- }
- }
-
- function get_type()
- {
- if ($this->type !== null)
- {
- return $this->type;
- }
- else
- {
- return null;
- }
- }
-
- function get_value()
- {
- if ($this->value !== null)
- {
- return $this->value;
- }
- else
- {
- return null;
- }
- }
-}
-
-/**
- * @todo Move to properly supporting RFC2616 (HTTP/1.1)
- */
-class SimplePie_File
-{
- var $url;
- var $useragent;
- var $success = true;
- var $headers = array();
- var $body;
- var $status_code;
- var $redirects = 0;
- var $error;
- var $method = SIMPLEPIE_FILE_SOURCE_NONE;
-
- function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
- {
- if (class_exists('idna_convert'))
- {
- $idn = new idna_convert;
- $parsed = SimplePie_Misc::parse_url($url);
- $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
- }
- $this->url = $url;
- $this->useragent = $useragent;
- if (preg_match('/^http(s)?:\/\//i', $url))
+ $links = $this->dom->getElementsByTagName('a');
+ foreach ($links as $link)
{
- if ($useragent === null)
- {
- $useragent = ini_get('user_agent');
- $this->useragent = $useragent;
- }
- if (!is_array($headers))
- {
- $headers = array();
- }
- if (!$force_fsockopen && function_exists('curl_exec'))
- {
- $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
- $fp = curl_init();
- $headers2 = array();
- foreach ($headers as $key => $value)
- {
- $headers2[] = "$key: $value";
- }
- if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
- {
- curl_setopt($fp, CURLOPT_ENCODING, '');
- }
- curl_setopt($fp, CURLOPT_URL, $url);
- curl_setopt($fp, CURLOPT_HEADER, 1);
- curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
- curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
- curl_setopt($fp, CURLOPT_REFERER, $url);
- curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
- curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
- if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
- {
- curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
- curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
- }
-
- $this->headers = curl_exec($fp);
- if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
- {
- curl_setopt($fp, CURLOPT_ENCODING, 'none');
- $this->headers = curl_exec($fp);
- }
- if (curl_errno($fp))
- {
- $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
- $this->success = false;
- }
- else
- {
- $info = curl_getinfo($fp);
- curl_close($fp);
- $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
- $this->headers = array_pop($this->headers);
- $parser = new SimplePie_HTTP_Parser($this->headers);
- if ($parser->parse())
- {
- $this->headers = $parser->headers;
- $this->body = $parser->body;
- $this->status_code = $parser->status_code;
- if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
- {
- $this->redirects++;
- $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
- return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
- }
- }
- }
- }
- else
+ if ($link->hasAttribute('href'))
{
- $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
- $url_parts = parse_url($url);
- $socket_host = $url_parts['host'];
- if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
- {
- $socket_host = "ssl://$url_parts[host]";
- $url_parts['port'] = 443;
- }
- if (!isset($url_parts['port']))
- {
- $url_parts['port'] = 80;
- }
- $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
- if (!$fp)
- {
- $this->error = 'fsockopen error: ' . $errstr;
- $this->success = false;
- }
- else
+ $href = trim($link->getAttribute('href'));
+ $parsed = $this->registry->call('Misc', 'parse_url', array($href));
+ if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
{
- stream_set_timeout($fp, $timeout);
- if (isset($url_parts['path']))
+ if ($this->base_location < $link->getLineNo())
{
- if (isset($url_parts['query']))
- {
- $get = "$url_parts[path]?$url_parts[query]";
- }
- else
- {
- $get = $url_parts['path'];
- }
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
}
else
{
- $get = '/';
- }
- $out = "GET $get HTTP/1.0\r\n";
- $out .= "Host: $url_parts[host]\r\n";
- $out .= "User-Agent: $useragent\r\n";
- if (extension_loaded('zlib'))
- {
- $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
- }
-
- if (isset($url_parts['user']) && isset($url_parts['pass']))
- {
- $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
}
- foreach ($headers as $key => $value)
+ if ($href === false)
{
- $out .= "$key: $value\r\n";
+ continue;
}
- $out .= "Connection: Close\r\n\r\n";
- fwrite($fp, $out);
- $info = stream_get_meta_data($fp);
+ $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
- $this->headers = '';
- while (!$info['eof'] && !$info['timed_out'])
- {
- $this->headers .= fread($fp, 1160);
- $info = stream_get_meta_data($fp);
- }
- if (!$info['timed_out'])
+ if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
{
- $parser = new SimplePie_HTTP_Parser($this->headers);
- if ($parser->parse())
- {
- $this->headers = $parser->headers;
- $this->body = $parser->body;
- $this->status_code = $parser->status_code;
- if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
- {
- $this->redirects++;
- $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
- return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
- }
- if (isset($this->headers['content-encoding']))
- {
- // Hey, we act dumb elsewhere, so let's do that here too
- switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
- {
- case 'gzip':
- case 'x-gzip':
- $decoder = new SimplePie_gzdecode($this->body);
- if (!$decoder->parse())
- {
- $this->error = 'Unable to decode HTTP "gzip" stream';
- $this->success = false;
- }
- else
- {
- $this->body = $decoder->data;
- }
- break;
-
- case 'deflate':
- if (($body = gzuncompress($this->body)) === false)
- {
- if (($body = gzinflate($this->body)) === false)
- {
- $this->error = 'Unable to decode HTTP "deflate" stream';
- $this->success = false;
- }
- }
- $this->body = $body;
- break;
-
- default:
- $this->error = 'Unknown content coding';
- $this->success = false;
- }
- }
- }
+ $this->local[] = $href;
}
else
{
- $this->error = 'fsocket timed out';
- $this->success = false;
+ $this->elsewhere[] = $href;
}
- fclose($fp);
}
}
}
- else
- {
- $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
- if (!$this->body = file_get_contents($url))
- {
- $this->error = 'file_get_contents could not read the file';
- $this->success = false;
- }
- }
- }
-}
-
-/**
- * HTTP Response Parser
- *
- * @package SimplePie
- */
-class SimplePie_HTTP_Parser
-{
- /**
- * HTTP Version
- *
- * @access public
- * @var float
- */
- var $http_version = 0.0;
-
- /**
- * Status code
- *
- * @access public
- * @var int
- */
- var $status_code = 0;
-
- /**
- * Reason phrase
- *
- * @access public
- * @var string
- */
- var $reason = '';
-
- /**
- * Key/value pairs of the headers
- *
- * @access public
- * @var array
- */
- var $headers = array();
-
- /**
- * Body of the response
- *
- * @access public
- * @var string
- */
- var $body = '';
-
- /**
- * Current state of the state machine
- *
- * @access private
- * @var string
- */
- var $state = 'http_version';
-
- /**
- * Input data
- *
- * @access private
- * @var string
- */
- var $data = '';
-
- /**
- * Input data length (to avoid calling strlen() everytime this is needed)
- *
- * @access private
- * @var int
- */
- var $data_length = 0;
-
- /**
- * Current position of the pointer
- *
- * @var int
- * @access private
- */
- var $position = 0;
-
- /**
- * Name of the hedaer currently being parsed
- *
- * @access private
- * @var string
- */
- var $name = '';
-
- /**
- * Value of the hedaer currently being parsed
- *
- * @access private
- * @var string
- */
- var $value = '';
-
- /**
- * Create an instance of the class with the input data
- *
- * @access public
- * @param string $data Input data
- */
- function SimplePie_HTTP_Parser($data)
- {
- $this->data = $data;
- $this->data_length = strlen($this->data);
- }
-
- /**
- * Parse the input data
- *
- * @access public
- * @return bool true on success, false on failure
- */
- function parse()
- {
- while ($this->state && $this->state !== 'emit' && $this->has_data())
- {
- $state = $this->state;
- $this->$state();
- }
- $this->data = '';
- if ($this->state === 'emit' || $this->state === 'body')
+ $this->local = array_unique($this->local);
+ $this->elsewhere = array_unique($this->elsewhere);
+ if (!empty($this->local) || !empty($this->elsewhere))
{
return true;
}
- else
- {
- $this->http_version = '';
- $this->status_code = '';
- $this->reason = '';
- $this->headers = array();
- $this->body = '';
- return false;
- }
- }
-
- /**
- * Check whether there is data beyond the pointer
- *
- * @access private
- * @return bool true if there is further data, false if not
- */
- function has_data()
- {
- return (bool) ($this->position < $this->data_length);
- }
-
- /**
- * See if the next character is LWS
- *
- * @access private
- * @return bool true if the next character is LWS, false if not
- */
- function is_linear_whitespace()
- {
- return (bool) ($this->data[$this->position] === "\x09"
- || $this->data[$this->position] === "\x20"
- || ($this->data[$this->position] === "\x0A"
- && isset($this->data[$this->position + 1])
- && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
- }
-
- /**
- * Parse the HTTP version
- *
- * @access private
- */
- function http_version()
- {
- if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
- {
- $len = strspn($this->data, '0123456789.', 5);
- $this->http_version = substr($this->data, 5, $len);
- $this->position += 5 + $len;
- if (substr_count($this->http_version, '.') <= 1)
- {
- $this->http_version = (float) $this->http_version;
- $this->position += strspn($this->data, "\x09\x20", $this->position);
- $this->state = 'status';
- }
- else
- {
- $this->state = false;
- }
- }
- else
- {
- $this->state = false;
- }
- }
-
- /**
- * Parse the status code
- *
- * @access private
- */
- function status()
- {
- if ($len = strspn($this->data, '0123456789', $this->position))
- {
- $this->status_code = (int) substr($this->data, $this->position, $len);
- $this->position += $len;
- $this->state = 'reason';
- }
- else
- {
- $this->state = false;
- }
- }
-
- /**
- * Parse the reason phrase
- *
- * @access private
- */
- function reason()
- {
- $len = strcspn($this->data, "\x0A", $this->position);
- $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
- $this->position += $len + 1;
- $this->state = 'new_line';
- }
-
- /**
- * Deal with a new line, shifting data around as needed
- *
- * @access private
- */
- function new_line()
- {
- $this->value = trim($this->value, "\x0D\x20");
- if ($this->name !== '' && $this->value !== '')
- {
- $this->name = strtolower($this->name);
- if (isset($this->headers[$this->name]))
- {
- $this->headers[$this->name] .= ', ' . $this->value;
- }
- else
- {
- $this->headers[$this->name] = $this->value;
- }
- }
- $this->name = '';
- $this->value = '';
- if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
- {
- $this->position += 2;
- $this->state = 'body';
- }
- elseif ($this->data[$this->position] === "\x0A")
- {
- $this->position++;
- $this->state = 'body';
- }
- else
- {
- $this->state = 'name';
- }
- }
-
- /**
- * Parse a header name
- *
- * @access private
- */
- function name()
- {
- $len = strcspn($this->data, "\x0A:", $this->position);
- if (isset($this->data[$this->position + $len]))
- {
- if ($this->data[$this->position + $len] === "\x0A")
- {
- $this->position += $len;
- $this->state = 'new_line';
- }
- else
- {
- $this->name = substr($this->data, $this->position, $len);
- $this->position += $len + 1;
- $this->state = 'value';
- }
- }
- else
- {
- $this->state = false;
- }
- }
-
- /**
- * Parse LWS, replacing consecutive LWS characters with a single space
- *
- * @access private
- */
- function linear_whitespace()
- {
- do
- {
- if (substr($this->data, $this->position, 2) === "\x0D\x0A")
- {
- $this->position += 2;
- }
- elseif ($this->data[$this->position] === "\x0A")
- {
- $this->position++;
- }
- $this->position += strspn($this->data, "\x09\x20", $this->position);
- } while ($this->has_data() && $this->is_linear_whitespace());
- $this->value .= "\x20";
- }
-
- /**
- * See what state to move to while within non-quoted header values
- *
- * @access private
- */
- function value()
- {
- if ($this->is_linear_whitespace())
- {
- $this->linear_whitespace();
- }
- else
- {
- switch ($this->data[$this->position])
- {
- case '"':
- $this->position++;
- $this->state = 'quote';
- break;
-
- case "\x0A":
- $this->position++;
- $this->state = 'new_line';
- break;
-
- default:
- $this->state = 'value_char';
- break;
- }
- }
- }
-
- /**
- * Parse a header value while outside quotes
- *
- * @access private
- */
- function value_char()
- {
- $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
- $this->value .= substr($this->data, $this->position, $len);
- $this->position += $len;
- $this->state = 'value';
- }
-
- /**
- * See what state to move to while within quoted header values
- *
- * @access private
- */
- function quote()
- {
- if ($this->is_linear_whitespace())
- {
- $this->linear_whitespace();
- }
- else
- {
- switch ($this->data[$this->position])
- {
- case '"':
- $this->position++;
- $this->state = 'value';
- break;
-
- case "\x0A":
- $this->position++;
- $this->state = 'new_line';
- break;
-
- case '\\':
- $this->position++;
- $this->state = 'quote_escaped';
- break;
-
- default:
- $this->state = 'quote_char';
- break;
- }
- }
- }
-
- /**
- * Parse a header value while within quotes
- *
- * @access private
- */
- function quote_char()
- {
- $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
- $this->value .= substr($this->data, $this->position, $len);
- $this->position += $len;
- $this->state = 'value';
- }
-
- /**
- * Parse an escaped character within quotes
- *
- * @access private
- */
- function quote_escaped()
- {
- $this->value .= $this->data[$this->position];
- $this->position++;
- $this->state = 'quote';
- }
-
- /**
- * Parse the body
- *
- * @access private
- */
- function body()
- {
- $this->body = substr($this->data, $this->position);
- $this->state = 'emit';
- }
-}
-
-/**
- * gzdecode
- *
- * @package SimplePie
- */
-class SimplePie_gzdecode
-{
- /**
- * Compressed data
- *
- * @access private
- * @see gzdecode::$data
- */
- var $compressed_data;
-
- /**
- * Size of compressed data
- *
- * @access private
- */
- var $compressed_size;
-
- /**
- * Minimum size of a valid gzip string
- *
- * @access private
- */
- var $min_compressed_size = 18;
-
- /**
- * Current position of pointer
- *
- * @access private
- */
- var $position = 0;
-
- /**
- * Flags (FLG)
- *
- * @access private
- */
- var $flags;
-
- /**
- * Uncompressed data
- *
- * @access public
- * @see gzdecode::$compressed_data
- */
- var $data;
-
- /**
- * Modified time
- *
- * @access public
- */
- var $MTIME;
-
- /**
- * Extra Flags
- *
- * @access public
- */
- var $XFL;
-
- /**
- * Operating System
- *
- * @access public
- */
- var $OS;
-
- /**
- * Subfield ID 1
- *
- * @access public
- * @see gzdecode::$extra_field
- * @see gzdecode::$SI2
- */
- var $SI1;
-
- /**
- * Subfield ID 2
- *
- * @access public
- * @see gzdecode::$extra_field
- * @see gzdecode::$SI1
- */
- var $SI2;
-
- /**
- * Extra field content
- *
- * @access public
- * @see gzdecode::$SI1
- * @see gzdecode::$SI2
- */
- var $extra_field;
-
- /**
- * Original filename
- *
- * @access public
- */
- var $filename;
-
- /**
- * Human readable comment
- *
- * @access public
- */
- var $comment;
-
- /**
- * Don't allow anything to be set
- *
- * @access public
- */
- function __set($name, $value)
- {
- trigger_error("Cannot write property $name", E_USER_ERROR);
- }
-
- /**
- * Set the compressed string and related properties
- *
- * @access public
- */
- function SimplePie_gzdecode($data)
- {
- $this->compressed_data = $data;
- $this->compressed_size = strlen($data);
+ return null;
}
- /**
- * Decode the GZIP stream
- *
- * @access public
- */
- function parse()
+ public function extension(&$array)
{
- if ($this->compressed_size >= $this->min_compressed_size)
+ foreach ($array as $key => $value)
{
- // Check ID1, ID2, and CM
- if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
- {
- return false;
- }
-
- // Get the FLG (FLaGs)
- $this->flags = ord($this->compressed_data[3]);
-
- // FLG bits above (1 << 4) are reserved
- if ($this->flags > 0x1F)
- {
- return false;
- }
-
- // Advance the pointer after the above
- $this->position += 4;
-
- // MTIME
- $mtime = substr($this->compressed_data, $this->position, 4);
- // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
- if (current(unpack('S', "\x00\x01")) === 1)
- {
- $mtime = strrev($mtime);
- }
- $this->MTIME = current(unpack('l', $mtime));
- $this->position += 4;
-
- // Get the XFL (eXtra FLags)
- $this->XFL = ord($this->compressed_data[$this->position++]);
-
- // Get the OS (Operating System)
- $this->OS = ord($this->compressed_data[$this->position++]);
-
- // Parse the FEXTRA
- if ($this->flags & 4)
- {
- // Read subfield IDs
- $this->SI1 = $this->compressed_data[$this->position++];
- $this->SI2 = $this->compressed_data[$this->position++];
-
- // SI2 set to zero is reserved for future use
- if ($this->SI2 === "\x00")
- {
- return false;
- }
-
- // Get the length of the extra field
- $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
- $this->position += 2;
-
- // Check the length of the string is still valid
- $this->min_compressed_size += $len + 4;
- if ($this->compressed_size >= $this->min_compressed_size)
- {
- // Set the extra field to the given data
- $this->extra_field = substr($this->compressed_data, $this->position, $len);
- $this->position += $len;
- }
- else
- {
- return false;
- }
- }
-
- // Parse the FNAME
- if ($this->flags & 8)
- {
- // Get the length of the filename
- $len = strcspn($this->compressed_data, "\x00", $this->position);
-
- // Check the length of the string is still valid
- $this->min_compressed_size += $len + 1;
- if ($this->compressed_size >= $this->min_compressed_size)
- {
- // Set the original filename to the given string
- $this->filename = substr($this->compressed_data, $this->position, $len);
- $this->position += $len + 1;
- }
- else
- {
- return false;
- }
- }
-
- // Parse the FCOMMENT
- if ($this->flags & 16)
- {
- // Get the length of the comment
- $len = strcspn($this->compressed_data, "\x00", $this->position);
-
- // Check the length of the string is still valid
- $this->min_compressed_size += $len + 1;
- if ($this->compressed_size >= $this->min_compressed_size)
- {
- // Set the original comment to the given string
- $this->comment = substr($this->compressed_data, $this->position, $len);
- $this->position += $len + 1;
- }
- else
- {
- return false;
- }
- }
-
- // Parse the FHCRC
- if ($this->flags & 2)
- {
- // Check the length of the string is still valid
- $this->min_compressed_size += $len + 2;
- if ($this->compressed_size >= $this->min_compressed_size)
- {
- // Read the CRC
- $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
-
- // Check the CRC matches
- if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
- {
- $this->position += 2;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
-
- // Decompress the actual data
- if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
- {
- return false;
- }
- else
- {
- $this->position = $this->compressed_size - 8;
- }
-
- // Check CRC of data
- $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
- $this->position += 4;
- /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
- {
- return false;
- }*/
-
- // Check ISIZE of data
- $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
- $this->position += 4;
- if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
+ if ($this->checked_feeds === $this->max_checked_feeds)
{
- return false;
- }
-
- // Wow, against all odds, we've actually got a valid gzip string
- return true;
- }
- else
- {
- return false;
- }
- }
-}
-
-class SimplePie_Cache
-{
- /**
- * Don't call the constructor. Please.
- *
- * @access private
- */
- function SimplePie_Cache()
- {
- trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR);
- }
-
- /**
- * Create a new SimplePie_Cache object
- *
- * @static
- * @access public
- */
- function create($location, $filename, $extension)
- {
- $location_iri = new SimplePie_IRI($location);
- switch ($location_iri->get_scheme())
- {
- case 'mysql':
- if (extension_loaded('mysql'))
- {
- return new SimplePie_Cache_MySQL($location_iri, $filename, $extension);
- }
break;
-
- default:
- return new SimplePie_Cache_File($location, $filename, $extension);
- }
- }
-}
-
-class SimplePie_Cache_File
-{
- var $location;
- var $filename;
- var $extension;
- var $name;
-
- function SimplePie_Cache_File($location, $filename, $extension)
- {
- $this->location = $location;
- $this->filename = $filename;
- $this->extension = $extension;
- $this->name = "$this->location/$this->filename.$this->extension";
- }
-
- function save($data)
- {
- if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
- {
- if (is_a($data, 'SimplePie'))
- {
- $data = $data->data;
- }
-
- $data = serialize($data);
-
- if (function_exists('file_put_contents'))
- {
- return (bool) file_put_contents($this->name, $data);
- }
- else
- {
- $fp = fopen($this->name, 'wb');
- if ($fp)
- {
- fwrite($fp, $data);
- fclose($fp);
- return true;
- }
- }
- }
- return false;
- }
-
- function load()
- {
- if (file_exists($this->name) && is_readable($this->name))
- {
- return unserialize(file_get_contents($this->name));
- }
- return false;
- }
-
- function mtime()
- {
- if (file_exists($this->name))
- {
- return filemtime($this->name);
- }
- return false;
- }
-
- function touch()
- {
- if (file_exists($this->name))
- {
- return touch($this->name);
- }
- return false;
- }
-
- function unlink()
- {
- if (file_exists($this->name))
- {
- return unlink($this->name);
- }
- return false;
- }
-}
-
-class SimplePie_Cache_DB
-{
- function prepare_simplepie_object_for_cache($data)
- {
- $items = $data->get_items();
- $items_by_id = array();
-
- if (!empty($items))
- {
- foreach ($items as $item)
- {
- $items_by_id[$item->get_id()] = $item;
- }
-
- if (count($items_by_id) !== count($items))
- {
- $items_by_id = array();
- foreach ($items as $item)
- {
- $items_by_id[$item->get_id(true)] = $item;
- }
- }
-
- if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
- {
- $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
- }
- elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
- {
- $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
- }
- elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
- {
- $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
- }
- elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
- {
- $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
- }
- else
- {
- $channel = null;
- }
-
- if ($channel !== null)
- {
- if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
- {
- unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
- }
- if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
- {
- unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
- }
- if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
- {
- unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
- }
- if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
- {
- unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
- }
- if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
- {
- unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
- }
- }
- if (isset($data->data['items']))
- {
- unset($data->data['items']);
- }
- if (isset($data->data['ordered_items']))
- {
- unset($data->data['ordered_items']);
- }
- }
- return array(serialize($data->data), $items_by_id);
- }
-}
-
-class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
-{
- var $mysql;
- var $options;
- var $id;
-
- function SimplePie_Cache_MySQL($mysql_location, $name, $extension)
- {
- $host = $mysql_location->get_host();
- if (SimplePie_Misc::stripos($host, 'unix(') === 0 && substr($host, -1) === ')')
- {
- $server = ':' . substr($host, 5, -1);
- }
- else
- {
- $server = $host;
- if ($mysql_location->get_port() !== null)
- {
- $server .= ':' . $mysql_location->get_port();
- }
- }
-
- if (strpos($mysql_location->get_userinfo(), ':') !== false)
- {
- list($username, $password) = explode(':', $mysql_location->get_userinfo(), 2);
- }
- else
- {
- $username = $mysql_location->get_userinfo();
- $password = null;
- }
-
- if ($this->mysql = mysql_connect($server, $username, $password))
- {
- $this->id = $name . $extension;
- $this->options = SimplePie_Misc::parse_str($mysql_location->get_query());
- if (!isset($this->options['prefix'][0]))
- {
- $this->options['prefix'][0] = '';
- }
-
- if (mysql_select_db(ltrim($mysql_location->get_path(), '/'))
- && mysql_query('SET NAMES utf8')
- && ($query = mysql_unbuffered_query('SHOW TABLES')))
- {
- $db = array();
- while ($row = mysql_fetch_row($query))
- {
- $db[] = $row[0];
- }
-
- if (!in_array($this->options['prefix'][0] . 'cache_data', $db))
- {
- if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))'))
- {
- $this->mysql = null;
- }
- }
-
- if (!in_array($this->options['prefix'][0] . 'items', $db))
- {
- if (!mysql_query('CREATE TABLE `' . $this->options['prefix'][0] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))'))
- {
- $this->mysql = null;
- }
- }
- }
- else
- {
- $this->mysql = null;
}
- }
- }
-
- function save($data)
- {
- if ($this->mysql)
- {
- $feed_id = "'" . mysql_real_escape_string($this->id) . "'";
-
- if (is_a($data, 'SimplePie'))
+ if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
{
- if (SIMPLEPIE_PHP5)
- {
- // This keyword needs to defy coding standards for PHP4 compatibility
- $data = clone($data);
- }
-
- $prepared = $this->prepare_simplepie_object_for_cache($data);
-
- if ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql))
- {
- if (mysql_num_rows($query))
- {
- $items = count($prepared[1]);
- if ($items)
- {
- $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = ' . $items . ', `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id;
- }
- else
- {
- $sql = 'UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `data` = \'' . mysql_real_escape_string($prepared[0]) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id;
- }
-
- if (!mysql_query($sql, $this->mysql))
- {
- return false;
- }
- }
- elseif (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(' . $feed_id . ', ' . count($prepared[1]) . ', \'' . mysql_real_escape_string($prepared[0]) . '\', ' . time() . ')', $this->mysql))
- {
- return false;
- }
-
- $ids = array_keys($prepared[1]);
- if (!empty($ids))
- {
- foreach ($ids as $id)
- {
- $database_ids[] = mysql_real_escape_string($id);
- }
-
- if ($query = mysql_unbuffered_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'items` WHERE `id` = \'' . implode('\' OR `id` = \'', $database_ids) . '\' AND `feed_id` = ' . $feed_id, $this->mysql))
- {
- $existing_ids = array();
- while ($row = mysql_fetch_row($query))
- {
- $existing_ids[] = $row[0];
- }
-
- $new_ids = array_diff($ids, $existing_ids);
-
- foreach ($new_ids as $new_id)
- {
- if (!($date = $prepared[1][$new_id]->get_date('U')))
- {
- $date = time();
- }
+ $this->checked_feeds++;
- if (!mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(' . $feed_id . ', \'' . mysql_real_escape_string($new_id) . '\', \'' . mysql_real_escape_string(serialize($prepared[1][$new_id]->data)) . '\', ' . $date . ')', $this->mysql))
- {
- return false;
- }
- }
- return true;
- }
- }
- else
- {
- return true;
- }
- }
- }
- elseif ($query = mysql_query('SELECT `id` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = ' . $feed_id, $this->mysql))
- {
- if (mysql_num_rows($query))
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
+ if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
{
- if (mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `items` = 0, `data` = \'' . mysql_real_escape_string(serialize($data)) . '\', `mtime` = ' . time() . ' WHERE `id` = ' . $feed_id, $this->mysql))
- {
- return true;
- }
+ return $feed;
}
- elseif (mysql_query('INSERT INTO `' . $this->options['prefix'][0] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(\'' . mysql_real_escape_string($this->id) . '\', 0, \'' . mysql_real_escape_string(serialize($data)) . '\', ' . time() . ')', $this->mysql))
+ else
{
- return true;
+ unset($array[$key]);
}
}
}
- return false;
+ return null;
}
- function load()
+ public function body(&$array)
{
- if ($this->mysql && ($query = mysql_query('SELECT `items`, `data` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query)))
+ foreach ($array as $key => $value)
{
- $data = unserialize($row[1]);
-
- if (isset($this->options['items'][0]))
- {
- $items = (int) $this->options['items'][0];
- }
- else
+ if ($this->checked_feeds === $this->max_checked_feeds)
{
- $items = (int) $row[0];
+ break;
}
-
- if ($items !== 0)
+ if (preg_match('/(rss|rdf|atom|xml)/i', $value))
{
- if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
- {
- $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
- }
- elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
- {
- $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
- }
- elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
- {
- $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
- }
- elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
+ $this->checked_feeds++;
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
+ if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
{
- $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
+ return $feed;
}
else
{
- $feed = null;
- }
-
- if ($feed !== null)
- {
- $sql = 'SELECT `data` FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . '\' ORDER BY `posted` DESC';
- if ($items > 0)
- {
- $sql .= ' LIMIT ' . $items;
- }
-
- if ($query = mysql_unbuffered_query($sql, $this->mysql))
- {
- while ($row = mysql_fetch_row($query))
- {
- $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row[0]);
- }
- }
- else
- {
- return false;
- }
+ unset($array[$key]);
}
}
- return $data;
- }
- return false;
- }
-
- function mtime()
- {
- if ($this->mysql && ($query = mysql_query('SELECT `mtime` FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($row = mysql_fetch_row($query)))
- {
- return $row[0];
- }
- else
- {
- return false;
- }
- }
-
- function touch()
- {
- if ($this->mysql && ($query = mysql_query('UPDATE `' . $this->options['prefix'][0] . 'cache_data` SET `mtime` = ' . time() . ' WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && mysql_affected_rows($this->mysql))
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- function unlink()
- {
- if ($this->mysql && ($query = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'cache_data` WHERE `id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)) && ($query2 = mysql_query('DELETE FROM `' . $this->options['prefix'][0] . 'items` WHERE `feed_id` = \'' . mysql_real_escape_string($this->id) . "'", $this->mysql)))
- {
- return true;
- }
- else
- {
- return false;
}
+ return null;
}
}
+/**
+ * Miscellanous utilities
+ *
+ * @package SimplePie
+ */
class SimplePie_Misc
{
- function time_hms($seconds)
+ public static function time_hms($seconds)
{
$time = '';
@@ -9111,67 +12293,25 @@ class SimplePie_Misc
return $time;
}
- function absolutize_url($relative, $base)
+ public static function absolutize_url($relative, $base)
{
$iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
- return $iri->get_iri();
- }
-
- function remove_dot_segments($input)
- {
- $output = '';
- while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
+ if ($iri === false)
{
- // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
- if (strpos($input, '../') === 0)
- {
- $input = substr($input, 3);
- }
- elseif (strpos($input, './') === 0)
- {
- $input = substr($input, 2);
- }
- // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
- elseif (strpos($input, '/./') === 0)
- {
- $input = substr_replace($input, '/', 0, 3);
- }
- elseif ($input === '/.')
- {
- $input = '/';
- }
- // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
- elseif (strpos($input, '/../') === 0)
- {
- $input = substr_replace($input, '/', 0, 4);
- $output = substr_replace($output, '', strrpos($output, '/'));
- }
- elseif ($input === '/..')
- {
- $input = '/';
- $output = substr_replace($output, '', strrpos($output, '/'));
- }
- // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
- elseif ($input === '.' || $input === '..')
- {
- $input = '';
- }
- // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
- elseif (($pos = strpos($input, '/', 1)) !== false)
- {
- $output .= substr($input, 0, $pos);
- $input = substr_replace($input, '', 0, $pos);
- }
- else
- {
- $output .= $input;
- $input = '';
- }
+ return false;
}
- return $output . $input;
+ return $iri->get_uri();
}
- function get_element($realname, $string)
+ /**
+ * Get a HTML/XML element from a HTML string
+ *
+ * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
+ * @param string $realname Element name (including namespace prefix if applicable)
+ * @param string $string HTML document
+ * @return array
+ */
+ public static function get_element($realname, $string)
{
$return = array();
$name = preg_quote($realname, '/');
@@ -9208,7 +12348,7 @@ class SimplePie_Misc
return $return;
}
- function element_implode($element)
+ public static function element_implode($element)
{
$full = "<$element[tag]";
foreach ($element['attribs'] as $key => $value)
@@ -9227,7 +12367,7 @@ class SimplePie_Misc
return $full;
}
- function error($message, $level, $file, $line)
+ public static function error($message, $level, $file, $line)
{
if ((ini_get('error_reporting') & $level) > 0)
{
@@ -9254,7 +12394,7 @@ class SimplePie_Misc
}
$log_file = @ini_get('error_log');
- if (!empty($log_file) && ('syslog' != $log_file) && !@is_writable($log_file))
+ if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
{
$log_error = false;
}
@@ -9268,51 +12408,7 @@ class SimplePie_Misc
return $message;
}
- /**
- * If a file has been cached, retrieve and display it.
- *
- * This is most useful for caching images (get_favicon(), etc.),
- * however it works for all cached files. This WILL NOT display ANY
- * file/image/page/whatever, but rather only display what has already
- * been cached by SimplePie.
- *
- * @access public
- * @see SimplePie::get_favicon()
- * @param str $identifier_url URL that is used to identify the content.
- * This may or may not be the actual URL of the live content.
- * @param str $cache_location Location of SimplePie's cache. Defaults
- * to './cache'.
- * @param str $cache_extension The file extension that the file was
- * cached with. Defaults to 'spc'.
- * @param str $cache_class Name of the cache-handling class being used
- * in SimplePie. Defaults to 'SimplePie_Cache', and should be left
- * as-is unless you've overloaded the class.
- * @param str $cache_name_function Obsolete. Exists for backwards
- * compatibility reasons only.
- */
- function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5')
- {
- $cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension);
-
- if ($file = $cache->load())
- {
- if (isset($file['headers']['content-type']))
- {
- header('Content-type:' . $file['headers']['content-type']);
- }
- else
- {
- header('Content-type: application/octet-stream');
- }
- header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
- echo $file['body'];
- exit;
- }
-
- die('Cached file for ' . $identifier_url . ' cannot be found.');
- }
-
- function fix_protocol($url, $http = 1)
+ public static function fix_protocol($url, $http = 1)
{
$url = SimplePie_Misc::normalize_url($url);
$parsed = SimplePie_Misc::parse_url($url);
@@ -9344,36 +12440,36 @@ class SimplePie_Misc
}
}
- function parse_url($url)
+ public static function parse_url($url)
{
$iri = new SimplePie_IRI($url);
return array(
- 'scheme' => (string) $iri->get_scheme(),
- 'authority' => (string) $iri->get_authority(),
- 'path' => (string) $iri->get_path(),
- 'query' => (string) $iri->get_query(),
- 'fragment' => (string) $iri->get_fragment()
+ 'scheme' => (string) $iri->scheme,
+ 'authority' => (string) $iri->authority,
+ 'path' => (string) $iri->path,
+ 'query' => (string) $iri->query,
+ 'fragment' => (string) $iri->fragment
);
}
- function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
+ public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
{
$iri = new SimplePie_IRI('');
- $iri->set_scheme($scheme);
- $iri->set_authority($authority);
- $iri->set_path($path);
- $iri->set_query($query);
- $iri->set_fragment($fragment);
- return $iri->get_iri();
+ $iri->scheme = $scheme;
+ $iri->authority = $authority;
+ $iri->path = $path;
+ $iri->query = $query;
+ $iri->fragment = $fragment;
+ return $iri->get_uri();
}
- function normalize_url($url)
+ public static function normalize_url($url)
{
$iri = new SimplePie_IRI($url);
- return $iri->get_iri();
+ return $iri->get_uri();
}
- function percent_encoding_normalization($match)
+ public static function percent_encoding_normalization($match)
{
$integer = hexdec($match[1]);
if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
@@ -9387,56 +12483,28 @@ class SimplePie_Misc
}
/**
- * Remove bad UTF-8 bytes
- *
- * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C
- * FAQ: Multilingual Forms (modified to include full ASCII range)
- *
- * @author Geoffrey Sneddon
- * @see http://www.w3.org/International/questions/qa-forms-utf-8
- * @param string $str String to remove bad UTF-8 bytes from
- * @return string UTF-8 string
- */
- function utf8_bad_replace($str)
- {
- if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str)))
- {
- return $return;
- }
- elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8')))
- {
- return $return;
- }
- elseif (preg_match_all('/(?:[\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+/', $str, $matches))
- {
- return implode("\xEF\xBF\xBD", $matches[0]);
- }
- elseif ($str !== '')
- {
- return "\xEF\xBF\xBD";
- }
- else
- {
- return '';
- }
- }
-
- /**
* Converts a Windows-1252 encoded string to a UTF-8 encoded string
*
* @static
- * @access public
* @param string $string Windows-1252 encoded string
* @return string UTF-8 encoded string
*/
- function windows_1252_to_utf8($string)
+ public static function windows_1252_to_utf8($string)
{
static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
return strtr($string, $convert_table);
}
- function change_encoding($data, $input, $output)
+ /**
+ * Change a string from one encoding to another
+ *
+ * @param string $data Raw data in $input encoding
+ * @param string $input Encoding of $data
+ * @param string $output Encoding you want
+ * @return string|boolean False if we can't convert it
+ */
+ public static function change_encoding($data, $input, $output)
{
$input = SimplePie_Misc::encoding($input);
$output = SimplePie_Misc::encoding($output);
@@ -9461,12 +12529,12 @@ class SimplePie_Misc
return SimplePie_Misc::windows_1252_to_utf8($data);
}
// This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
- elseif (function_exists('mb_convert_encoding') && @mb_convert_encoding("\x80", 'UTF-16BE', $input) !== "\x00\x80" && in_array($input, mb_list_encodings()) && ($return = @mb_convert_encoding($data, $output, $input)))
+ elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
{
return $return;
- }
+ }
// This is last, as behaviour of this varies with OS userland and PHP version
- elseif (function_exists('iconv') && ($return = @iconv($input, $output, $data)))
+ elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
{
return $return;
}
@@ -9477,6 +12545,49 @@ class SimplePie_Misc
}
}
+ protected static function change_encoding_mbstring($data, $input, $output)
+ {
+ if ($input === 'windows-949')
+ {
+ $input = 'EUC-KR';
+ }
+ if ($output === 'windows-949')
+ {
+ $output = 'EUC-KR';
+ }
+ if ($input === 'Windows-31J')
+ {
+ $input = 'SJIS';
+ }
+ if ($output === 'Windows-31J')
+ {
+ $output = 'SJIS';
+ }
+
+ // Check that the encoding is supported
+ if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
+ {
+ return false;
+ }
+ if (!in_array($input, mb_list_encodings()))
+ {
+ return false;
+ }
+
+ // Let's do some conversion
+ if ($return = @mb_convert_encoding($data, $output, $input))
+ {
+ return $return;
+ }
+
+ return false;
+ }
+
+ protected static function change_encoding_iconv($data, $input, $output)
+ {
+ return @iconv($input, $output, $data);
+ }
+
/**
* Normalize an encoding name
*
@@ -9488,7 +12599,7 @@ class SimplePie_Misc
* @param string $charset Character set to standardise
* @return string Standardised name
*/
- function encoding($charset)
+ public static function encoding($charset)
{
// Normalization from UTS #22
switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
@@ -10801,7 +13912,7 @@ class SimplePie_Misc
}
}
- function get_curl_version()
+ public static function get_curl_version()
{
if (is_array($curl = curl_version()))
{
@@ -10822,48 +13933,13 @@ class SimplePie_Misc
return $curl;
}
- function is_subclass_of($class1, $class2)
- {
- if (func_num_args() !== 2)
- {
- trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING);
- }
- elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1))
- {
- return is_subclass_of($class1, $class2);
- }
- elseif (is_string($class1) && is_string($class2))
- {
- if (class_exists($class1))
- {
- if (class_exists($class2))
- {
- $class2 = strtolower($class2);
- while ($class1 = strtolower(get_parent_class($class1)))
- {
- if ($class1 === $class2)
- {
- return true;
- }
- }
- }
- }
- else
- {
- trigger_error('Unknown class passed as parameter', E_USER_WARNNG);
- }
- }
- return false;
- }
-
/**
* Strip HTML comments
*
- * @access public
* @param string $data Data to strip comments from
* @return string Comment stripped string
*/
- function strip_comments($data)
+ public static function strip_comments($data)
{
$output = '';
while (($start = strpos($data, '<!--')) !== false)
@@ -10881,7 +13957,7 @@ class SimplePie_Misc
return $output . $data;
}
- function parse_date($dt)
+ public static function parse_date($dt)
{
$parser = SimplePie_Parse_Date::get();
return $parser->parse($dt);
@@ -10890,12 +13966,11 @@ class SimplePie_Misc
/**
* Decode HTML entities
*
- * @static
- * @access public
+ * @deprecated Use DOMDocument instead
* @param string $data Input data
* @return string Output data
*/
- function entities_decode($data)
+ public static function entities_decode($data)
{
$decoder = new SimplePie_Decode_HTML_Entities($data);
return $decoder->parse();
@@ -10904,11 +13979,10 @@ class SimplePie_Misc
/**
* Remove RFC822 comments
*
- * @access public
* @param string $data Data to strip comments from
* @return string Comment stripped string
*/
- function uncomment_rfc822($string)
+ public static function uncomment_rfc822($string)
{
$string = (string) $string;
$position = 0;
@@ -10962,7 +14036,7 @@ class SimplePie_Misc
return $output;
}
- function parse_mime($mime)
+ public static function parse_mime($mime)
{
if (($pos = strpos($mime, ';')) === false)
{
@@ -10974,19 +14048,7 @@ class SimplePie_Misc
}
}
- function htmlspecialchars_decode($string, $quote_style)
- {
- if (function_exists('htmlspecialchars_decode'))
- {
- return htmlspecialchars_decode($string, $quote_style);
- }
- else
- {
- return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
- }
- }
-
- function atom_03_construct_type($attribs)
+ public static function atom_03_construct_type($attribs)
{
if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
{
@@ -11022,7 +14084,7 @@ class SimplePie_Misc
}
}
- function atom_10_construct_type($attribs)
+ public static function atom_10_construct_type($attribs)
{
if (isset($attribs['']['type']))
{
@@ -11044,7 +14106,7 @@ class SimplePie_Misc
return SIMPLEPIE_CONSTRUCT_TEXT;
}
- function atom_10_content_construct_type($attribs)
+ public static function atom_10_content_construct_type($attribs)
{
if (isset($attribs['']['type']))
{
@@ -11075,12 +14137,12 @@ class SimplePie_Misc
}
}
- function is_isegment_nz_nc($string)
+ public static function is_isegment_nz_nc($string)
{
return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
}
- function space_seperated_tokens($string)
+ public static function space_seperated_tokens($string)
{
$space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
$string_length = strlen($string);
@@ -11099,57 +14161,14 @@ class SimplePie_Misc
return $tokens;
}
- function array_unique($array)
- {
- if (version_compare(PHP_VERSION, '5.2', '>='))
- {
- return array_unique($array);
- }
- else
- {
- $array = (array) $array;
- $new_array = array();
- $new_array_strings = array();
- foreach ($array as $key => $value)
- {
- if (is_object($value))
- {
- if (method_exists($value, '__toString'))
- {
- $cmp = $value->__toString();
- }
- else
- {
- trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR);
- }
- }
- elseif (is_array($value))
- {
- $cmp = (string) reset($value);
- }
- else
- {
- $cmp = (string) $value;
- }
- if (!in_array($cmp, $new_array_strings))
- {
- $new_array[$key] = $value;
- $new_array_strings[] = $cmp;
- }
- }
- return $new_array;
- }
- }
-
/**
* Converts a unicode codepoint to a UTF-8 character
*
* @static
- * @access public
* @param int $codepoint Unicode codepoint
* @return string UTF-8 character
*/
- function codepoint_to_utf8($codepoint)
+ public static function codepoint_to_utf8($codepoint)
{
$codepoint = (int) $codepoint;
if ($codepoint < 0)
@@ -11180,60 +14199,16 @@ class SimplePie_Misc
}
/**
- * Re-implementation of PHP 5's stripos()
- *
- * Returns the numeric position of the first occurrence of needle in the
- * haystack string.
- *
- * @static
- * @access string
- * @param object $haystack
- * @param string $needle Note that the needle may be a string of one or more
- * characters. If needle is not a string, it is converted to an integer
- * and applied as the ordinal value of a character.
- * @param int $offset The optional offset parameter allows you to specify which
- * character in haystack to start searching. The position returned is still
- * relative to the beginning of haystack.
- * @return bool If needle is not found, stripos() will return boolean false.
- */
- function stripos($haystack, $needle, $offset = 0)
- {
- if (function_exists('stripos'))
- {
- return stripos($haystack, $needle, $offset);
- }
- else
- {
- if (is_string($needle))
- {
- $needle = strtolower($needle);
- }
- elseif (is_int($needle) || is_bool($needle) || is_double($needle))
- {
- $needle = strtolower(chr($needle));
- }
- else
- {
- trigger_error('needle is not a string or an integer', E_USER_WARNING);
- return false;
- }
-
- return strpos(strtolower($haystack), $needle, $offset);
- }
- }
-
- /**
* Similar to parse_str()
*
* Returns an associative array of name/value pairs, where the value is an
* array of values that have used the same name
*
* @static
- * @access string
* @param string $str The input string.
* @return array
*/
- function parse_str($str)
+ public static function parse_str($str)
{
$return = array();
$str = explode('&', $str);
@@ -11259,9 +14234,10 @@ class SimplePie_Misc
*
* @todo Add support for EBCDIC
* @param string $data XML data
+ * @param SimplePie_Registry $registry Class registry
* @return array Possible encodings
*/
- function xml_encoding($data)
+ public static function xml_encoding($data, $registry)
{
// UTF-32 Big Endian BOM
if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
@@ -11293,7 +14269,7 @@ class SimplePie_Misc
{
if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
{
- $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8'));
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
if ($parser->parse())
{
$encoding[] = $parser->encoding;
@@ -11306,7 +14282,7 @@ class SimplePie_Misc
{
if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
{
- $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8'));
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
if ($parser->parse())
{
$encoding[] = $parser->encoding;
@@ -11319,7 +14295,7 @@ class SimplePie_Misc
{
if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
{
- $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8'));
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
if ($parser->parse())
{
$encoding[] = $parser->encoding;
@@ -11332,7 +14308,7 @@ class SimplePie_Misc
{
if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
{
- $parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8'));
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
if ($parser->parse())
{
$encoding[] = $parser->encoding;
@@ -11345,7 +14321,7 @@ class SimplePie_Misc
{
if ($pos = strpos($data, "\x3F\x3E"))
{
- $parser = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
+ $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
if ($parser->parse())
{
$encoding[] = $parser->encoding;
@@ -11361,7 +14337,7 @@ class SimplePie_Misc
return $encoding;
}
- function output_javascript()
+ public static function output_javascript()
{
if (function_exists('ob_gzhandler'))
{
@@ -11371,10 +14347,6 @@ class SimplePie_Misc
header('Cache-Control: must-revalidate');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
?>
-function embed_odeo(link) {
- document.writeln('<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url='+link+'"></embed>');
-}
-
function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
if (placeholder != '') {
document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
@@ -11398,12 +14370,45 @@ function embed_wmedia(width, height, link) {
<?php
}
-
+ /**
+ * Get the SimplePie build timestamp
+ *
+ * Uses the git index if it exists, otherwise uses the modification time
+ * of the newest file.
+ */
+ public static function get_build()
+ {
+ $root = dirname(dirname(__FILE__));
+ if (file_exists($root . '/.git/index'))
+ {
+ return filemtime($root . '/.git/index');
+ }
+ elseif (file_exists($root . '/SimplePie'))
+ {
+ $time = 0;
+ foreach (glob($root . '/SimplePie/*.php') as $file)
+ {
+ if (($mtime = filemtime($file)) > $time)
+ {
+ $time = $mtime;
+ }
+ }
+ return $time;
+ }
+ elseif (file_exists(dirname(__FILE__) . '/Core.php'))
+ {
+ return filemtime(dirname(__FILE__) . '/Core.php');
+ }
+ else
+ {
+ return filemtime(__FILE__);
+ }
+ }
/**
* Format debugging information
*/
- function debug($sp)
+ public static function debug(&$sp)
{
$info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
$info .= 'PHP ' . PHP_VERSION . "\n";
@@ -11449,1158 +14454,10 @@ function embed_wmedia(width, height, link) {
}
return $info;
}
-}
-/**
- * Decode HTML Entities
- *
- * This implements HTML5 as of revision 967 (2007-06-28)
- *
- * @package SimplePie
- */
-class SimplePie_Decode_HTML_Entities
-{
- /**
- * Data to be parsed
- *
- * @access private
- * @var string
- */
- var $data = '';
-
- /**
- * Currently consumed bytes
- *
- * @access private
- * @var string
- */
- var $consumed = '';
-
- /**
- * Position of the current byte being parsed
- *
- * @access private
- * @var int
- */
- var $position = 0;
-
- /**
- * Create an instance of the class with the input data
- *
- * @access public
- * @param string $data Input data
- */
- function SimplePie_Decode_HTML_Entities($data)
+ public static function silence_errors($num, $str)
{
- $this->data = $data;
- }
-
- /**
- * Parse the input data
- *
- * @access public
- * @return string Output data
- */
- function parse()
- {
- while (($this->position = strpos($this->data, '&', $this->position)) !== false)
- {
- $this->consume();
- $this->entity();
- $this->consumed = '';
- }
- return $this->data;
- }
-
- /**
- * Consume the next byte
- *
- * @access private
- * @return mixed The next byte, or false, if there is no more data
- */
- function consume()
- {
- if (isset($this->data[$this->position]))
- {
- $this->consumed .= $this->data[$this->position];
- return $this->data[$this->position++];
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Consume a range of characters
- *
- * @access private
- * @param string $chars Characters to consume
- * @return mixed A series of characters that match the range, or false
- */
- function consume_range($chars)
- {
- if ($len = strspn($this->data, $chars, $this->position))
- {
- $data = substr($this->data, $this->position, $len);
- $this->consumed .= $data;
- $this->position += $len;
- return $data;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Unconsume one byte
- *
- * @access private
- */
- function unconsume()
- {
- $this->consumed = substr($this->consumed, 0, -1);
- $this->position--;
- }
-
- /**
- * Decode an entity
- *
- * @access private
- */
- function entity()
- {
- switch ($this->consume())
- {
- case "\x09":
- case "\x0A":
- case "\x0B":
- case "\x0B":
- case "\x0C":
- case "\x20":
- case "\x3C":
- case "\x26":
- case false:
- break;
-
- case "\x23":
- switch ($this->consume())
- {
- case "\x78":
- case "\x58":
- $range = '0123456789ABCDEFabcdef';
- $hex = true;
- break;
-
- default:
- $range = '0123456789';
- $hex = false;
- $this->unconsume();
- break;
- }
-
- if ($codepoint = $this->consume_range($range))
- {
- static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
-
- if ($hex)
- {
- $codepoint = hexdec($codepoint);
- }
- else
- {
- $codepoint = intval($codepoint);
- }
-
- if (isset($windows_1252_specials[$codepoint]))
- {
- $replacement = $windows_1252_specials[$codepoint];
- }
- else
- {
- $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
- }
-
- if (!in_array($this->consume(), array(';', false), true))
- {
- $this->unconsume();
- }
-
- $consumed_length = strlen($this->consumed);
- $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
- $this->position += strlen($replacement) - $consumed_length;
- }
- break;
-
- default:
- static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C");
-
- for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
- {
- $consumed = substr($this->consumed, 1);
- if (isset($entities[$consumed]))
- {
- $match = $consumed;
- }
- }
-
- if ($match !== null)
- {
- $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
- $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
- }
- break;
- }
- }
-}
-
-/**
- * IRI parser/serialiser
- *
- * @package SimplePie
- */
-class SimplePie_IRI
-{
- /**
- * Scheme
- *
- * @access private
- * @var string
- */
- var $scheme;
-
- /**
- * User Information
- *
- * @access private
- * @var string
- */
- var $userinfo;
-
- /**
- * Host
- *
- * @access private
- * @var string
- */
- var $host;
-
- /**
- * Port
- *
- * @access private
- * @var string
- */
- var $port;
-
- /**
- * Path
- *
- * @access private
- * @var string
- */
- var $path;
-
- /**
- * Query
- *
- * @access private
- * @var string
- */
- var $query;
-
- /**
- * Fragment
- *
- * @access private
- * @var string
- */
- var $fragment;
-
- /**
- * Whether the object represents a valid IRI
- *
- * @access private
- * @var array
- */
- var $valid = array();
-
- /**
- * Return the entire IRI when you try and read the object as a string
- *
- * @access public
- * @return string
- */
- function __toString()
- {
- return $this->get_iri();
- }
-
- /**
- * Create a new IRI object, from a specified string
- *
- * @access public
- * @param string $iri
- * @return SimplePie_IRI
- */
- function SimplePie_IRI($iri)
- {
- $iri = (string) $iri;
- if ($iri !== '')
- {
- $parsed = $this->parse_iri($iri);
- $this->set_scheme($parsed['scheme']);
- $this->set_authority($parsed['authority']);
- $this->set_path($parsed['path']);
- $this->set_query($parsed['query']);
- $this->set_fragment($parsed['fragment']);
- }
- }
-
- /**
- * Create a new IRI object by resolving a relative IRI
- *
- * @static
- * @access public
- * @param SimplePie_IRI $base Base IRI
- * @param string $relative Relative IRI
- * @return SimplePie_IRI
- */
- function absolutize($base, $relative)
- {
- $relative = (string) $relative;
- if ($relative !== '')
- {
- $relative = new SimplePie_IRI($relative);
- if ($relative->get_scheme() !== null)
- {
- $target = $relative;
- }
- elseif ($base->get_iri() !== null)
- {
- if ($relative->get_authority() !== null)
- {
- $target = $relative;
- $target->set_scheme($base->get_scheme());
- }
- else
- {
- $target = new SimplePie_IRI('');
- $target->set_scheme($base->get_scheme());
- $target->set_userinfo($base->get_userinfo());
- $target->set_host($base->get_host());
- $target->set_port($base->get_port());
- if ($relative->get_path() !== null)
- {
- if (strpos($relative->get_path(), '/') === 0)
- {
- $target->set_path($relative->get_path());
- }
- elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null)
- {
- $target->set_path('/' . $relative->get_path());
- }
- elseif (($last_segment = strrpos($base->get_path(), '/')) !== false)
- {
- $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path());
- }
- else
- {
- $target->set_path($relative->get_path());
- }
- $target->set_query($relative->get_query());
- }
- else
- {
- $target->set_path($base->get_path());
- if ($relative->get_query() !== null)
- {
- $target->set_query($relative->get_query());
- }
- elseif ($base->get_query() !== null)
- {
- $target->set_query($base->get_query());
- }
- }
- }
- $target->set_fragment($relative->get_fragment());
- }
- else
- {
- // No base URL, just return the relative URL
- $target = $relative;
- }
- }
- else
- {
- $target = $base;
- }
- return $target;
- }
-
- /**
- * Parse an IRI into scheme/authority/path/query/fragment segments
- *
- * @access private
- * @param string $iri
- * @return array
- */
- function parse_iri($iri)
- {
- preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match);
- for ($i = count($match); $i <= 9; $i++)
- {
- $match[$i] = '';
- }
- return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]);
- }
-
- /**
- * Remove dot segments from a path
- *
- * @access private
- * @param string $input
- * @return string
- */
- function remove_dot_segments($input)
- {
- $output = '';
- while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
- {
- // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
- if (strpos($input, '../') === 0)
- {
- $input = substr($input, 3);
- }
- elseif (strpos($input, './') === 0)
- {
- $input = substr($input, 2);
- }
- // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
- elseif (strpos($input, '/./') === 0)
- {
- $input = substr_replace($input, '/', 0, 3);
- }
- elseif ($input === '/.')
- {
- $input = '/';
- }
- // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
- elseif (strpos($input, '/../') === 0)
- {
- $input = substr_replace($input, '/', 0, 4);
- $output = substr_replace($output, '', strrpos($output, '/'));
- }
- elseif ($input === '/..')
- {
- $input = '/';
- $output = substr_replace($output, '', strrpos($output, '/'));
- }
- // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
- elseif ($input === '.' || $input === '..')
- {
- $input = '';
- }
- // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
- elseif (($pos = strpos($input, '/', 1)) !== false)
- {
- $output .= substr($input, 0, $pos);
- $input = substr_replace($input, '', 0, $pos);
- }
- else
- {
- $output .= $input;
- $input = '';
- }
- }
- return $output . $input;
- }
-
- /**
- * Replace invalid character with percent encoding
- *
- * @param string $string Input string
- * @param string $valid_chars Valid characters
- * @param int $case Normalise case
- * @return string
- */
- function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE, $iprivate = false)
- {
- // Normalize as many pct-encoded sections as possible
- $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
-
- // Replace invalid percent characters
- $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
-
- // Add unreserved and % to $valid_chars (the latter is safe because all
- // pct-encoded sections are now valid).
- $valid_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
-
- // Now replace any bytes that aren't allowed with their pct-encoded versions
- $position = 0;
- $strlen = strlen($string);
- while (($position += strspn($string, $valid_chars, $position)) < $strlen)
- {
- $value = ord($string[$position]);
-
- // Start position
- $start = $position;
-
- // By default we are valid
- $valid = true;
-
- // No one byte sequences are valid due to the while.
- // Two byte sequence:
- if (($value & 0xE0) === 0xC0)
- {
- $character = ($value & 0x1F) << 6;
- $length = 2;
- $remaining = 1;
- }
- // Three byte sequence:
- elseif (($value & 0xF0) === 0xE0)
- {
- $character = ($value & 0x0F) << 12;
- $length = 3;
- $remaining = 2;
- }
- // Four byte sequence:
- elseif (($value & 0xF8) === 0xF0)
- {
- $character = ($value & 0x07) << 18;
- $length = 4;
- $remaining = 3;
- }
- // Invalid byte:
- else
- {
- $valid = false;
- $length = 1;
- $remaining = 0;
- }
-
- if ($remaining)
- {
- if ($position + $length <= $strlen)
- {
- for ($position++; $remaining; $position++)
- {
- $value = ord($string[$position]);
-
- // Check that the byte is valid, then add it to the character:
- if (($value & 0xC0) === 0x80)
- {
- $character |= ($value & 0x3F) << (--$remaining * 6);
- }
- // If it is invalid, count the sequence as invalid and reprocess the current byte:
- else
- {
- $valid = false;
- $position--;
- break;
- }
- }
- }
- else
- {
- $position = $strlen - 1;
- $valid = false;
- }
- }
-
- // Percent encode anything invalid or not in ucschar
- if (
- // Invalid sequences
- !$valid
- // Non-shortest form sequences are invalid
- || $length > 1 && $character <= 0x7F
- || $length > 2 && $character <= 0x7FF
- || $length > 3 && $character <= 0xFFFF
- // Outside of range of ucschar codepoints
- // Noncharacters
- || ($character & 0xFFFE) === 0xFFFE
- || $character >= 0xFDD0 && $character <= 0xFDEF
- || (
- // Everything else not in ucschar
- $character > 0xD7FF && $character < 0xF900
- || $character < 0xA0
- || $character > 0xEFFFD
- )
- && (
- // Everything not in iprivate, if it applies
- !$iprivate
- || $character < 0xE000
- || $character > 0x10FFFD
- )
- )
- {
- // If we were a character, pretend we weren't, but rather an error.
- if ($valid)
- $position--;
-
- for ($j = $start; $j <= $position; $j++)
- {
- $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
- $j += 2;
- $position += 2;
- $strlen += 2;
- }
- }
- }
-
- // Normalise case
- if ($case & SIMPLEPIE_LOWERCASE)
- {
- $string = strtolower($string);
- }
- elseif ($case & SIMPLEPIE_UPPERCASE)
- {
- $string = strtoupper($string);
- }
-
- return $string;
- }
-
- /**
- * Callback function for preg_replace_callback.
- *
- * Removes sequences of percent encoded bytes that represent UTF-8
- * encoded characters in iunreserved
- *
- * @access private
- * @param array $match PCRE match
- * @return string Replacement
- */
- function remove_iunreserved_percent_encoded($match)
- {
- // As we just have valid percent encoded sequences we can just explode
- // and ignore the first member of the returned array (an empty string).
- $bytes = explode('%', $match[0]);
-
- // Initialize the new string (this is what will be returned) and that
- // there are no bytes remaining in the current sequence (unsurprising
- // at the first byte!).
- $string = '';
- $remaining = 0;
-
- // Loop over each and every byte, and set $value to its value
- for ($i = 1, $len = count($bytes); $i < $len; $i++)
- {
- $value = hexdec($bytes[$i]);
-
- // If we're the first byte of sequence:
- if (!$remaining)
- {
- // Start position
- $start = $i;
-
- // By default we are valid
- $valid = true;
-
- // One byte sequence:
- if ($value <= 0x7F)
- {
- $character = $value;
- $length = 1;
- }
- // Two byte sequence:
- elseif (($value & 0xE0) === 0xC0)
- {
- $character = ($value & 0x1F) << 6;
- $length = 2;
- $remaining = 1;
- }
- // Three byte sequence:
- elseif (($value & 0xF0) === 0xE0)
- {
- $character = ($value & 0x0F) << 12;
- $length = 3;
- $remaining = 2;
- }
- // Four byte sequence:
- elseif (($value & 0xF8) === 0xF0)
- {
- $character = ($value & 0x07) << 18;
- $length = 4;
- $remaining = 3;
- }
- // Invalid byte:
- else
- {
- $valid = false;
- $remaining = 0;
- }
- }
- // Continuation byte:
- else
- {
- // Check that the byte is valid, then add it to the character:
- if (($value & 0xC0) === 0x80)
- {
- $remaining--;
- $character |= ($value & 0x3F) << ($remaining * 6);
- }
- // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
- else
- {
- $valid = false;
- $remaining = 0;
- $i--;
- }
- }
-
- // If we've reached the end of the current byte sequence, append it to Unicode::$data
- if (!$remaining)
- {
- // Percent encode anything invalid or not in iunreserved
- if (
- // Invalid sequences
- !$valid
- // Non-shortest form sequences are invalid
- || $length > 1 && $character <= 0x7F
- || $length > 2 && $character <= 0x7FF
- || $length > 3 && $character <= 0xFFFF
- // Outside of range of iunreserved codepoints
- || $character < 0x2D
- || $character > 0xEFFFD
- // Noncharacters
- || ($character & 0xFFFE) === 0xFFFE
- || $character >= 0xFDD0 && $character <= 0xFDEF
- // Everything else not in iunreserved (this is all BMP)
- || $character === 0x2F
- || $character > 0x39 && $character < 0x41
- || $character > 0x5A && $character < 0x61
- || $character > 0x7A && $character < 0x7E
- || $character > 0x7E && $character < 0xA0
- || $character > 0xD7FF && $character < 0xF900
- )
- {
- for ($j = $start; $j <= $i; $j++)
- {
- $string .= '%' . strtoupper($bytes[$j]);
- }
- }
- else
- {
- for ($j = $start; $j <= $i; $j++)
- {
- $string .= chr(hexdec($bytes[$j]));
- }
- }
- }
- }
-
- // If we have any bytes left over they are invalid (i.e., we are
- // mid-way through a multi-byte sequence)
- if ($remaining)
- {
- for ($j = $start; $j < $len; $j++)
- {
- $string .= '%' . strtoupper($bytes[$j]);
- }
- }
-
- return $string;
- }
-
- /**
- * Check if the object represents a valid IRI
- *
- * @access public
- * @return bool
- */
- function is_valid()
- {
- return array_sum($this->valid) === count($this->valid);
- }
-
- /**
- * Set the scheme. Returns true on success, false on failure (if there are
- * any invalid characters).
- *
- * @access public
- * @param string $scheme
- * @return bool
- */
- function set_scheme($scheme)
- {
- if ($scheme === null || $scheme === '')
- {
- $this->scheme = null;
- }
- else
- {
- $len = strlen($scheme);
- switch (true)
- {
- case $len > 1:
- if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1))
- {
- $this->scheme = null;
- $this->valid[__FUNCTION__] = false;
- return false;
- }
-
- case $len > 0:
- if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1))
- {
- $this->scheme = null;
- $this->valid[__FUNCTION__] = false;
- return false;
- }
- }
- $this->scheme = strtolower($scheme);
- }
- $this->valid[__FUNCTION__] = true;
- return true;
- }
-
- /**
- * Set the authority. Returns true on success, false on failure (if there are
- * any invalid characters).
- *
- * @access public
- * @param string $authority
- * @return bool
- */
- function set_authority($authority)
- {
- if (($userinfo_end = strrpos($authority, '@')) !== false)
- {
- $userinfo = substr($authority, 0, $userinfo_end);
- $authority = substr($authority, $userinfo_end + 1);
- }
- else
- {
- $userinfo = null;
- }
-
- if (($port_start = strpos($authority, ':')) !== false)
- {
- $port = substr($authority, $port_start + 1);
- $authority = substr($authority, 0, $port_start);
- }
- else
- {
- $port = null;
- }
-
- return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port);
- }
-
- /**
- * Set the userinfo.
- *
- * @access public
- * @param string $userinfo
- * @return bool
- */
- function set_userinfo($userinfo)
- {
- if ($userinfo === null || $userinfo === '')
- {
- $this->userinfo = null;
- }
- else
- {
- $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:');
- }
- $this->valid[__FUNCTION__] = true;
- return true;
- }
-
- /**
- * Set the host. Returns true on success, false on failure (if there are
- * any invalid characters).
- *
- * @access public
- * @param string $host
- * @return bool
- */
- function set_host($host)
- {
- if ($host === null || $host === '')
- {
- $this->host = null;
- $this->valid[__FUNCTION__] = true;
- return true;
- }
- elseif ($host[0] === '[' && substr($host, -1) === ']')
- {
- if (Net_IPv6::checkIPv6(substr($host, 1, -1)))
- {
- $this->host = $host;
- $this->valid[__FUNCTION__] = true;
- return true;
- }
- else
- {
- $this->host = null;
- $this->valid[__FUNCTION__] = false;
- return false;
- }
- }
- else
- {
- $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE);
- $this->valid[__FUNCTION__] = true;
- return true;
- }
- }
-
- /**
- * Set the port. Returns true on success, false on failure (if there are
- * any invalid characters).
- *
- * @access public
- * @param string $port
- * @return bool
- */
- function set_port($port)
- {
- if ($port === null || $port === '')
- {
- $this->port = null;
- $this->valid[__FUNCTION__] = true;
- return true;
- }
- elseif (strspn($port, '0123456789') === strlen($port))
- {
- $this->port = (int) $port;
- $this->valid[__FUNCTION__] = true;
- return true;
- }
- else
- {
- $this->port = null;
- $this->valid[__FUNCTION__] = false;
- return false;
- }
- }
-
- /**
- * Set the path.
- *
- * @access public
- * @param string $path
- * @return bool
- */
- function set_path($path)
- {
- if ($path === null || $path === '')
- {
- $this->path = null;
- $this->valid[__FUNCTION__] = true;
- return true;
- }
- elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null)
- {
- $this->path = null;
- $this->valid[__FUNCTION__] = false;
- return false;
- }
- else
- {
- $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/');
- if ($this->scheme !== null)
- {
- $this->path = $this->remove_dot_segments($this->path);
- }
- $this->valid[__FUNCTION__] = true;
- return true;
- }
- }
-
- /**
- * Set the query.
- *
- * @access public
- * @param string $query
- * @return bool
- */
- function set_query($query)
- {
- if ($query === null || $query === '')
- {
- $this->query = null;
- }
- else
- {
- $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?&=');
- }
- $this->valid[__FUNCTION__] = true;
- return true;
- }
-
- /**
- * Set the fragment.
- *
- * @access public
- * @param string $fragment
- * @return bool
- */
- function set_fragment($fragment)
- {
- if ($fragment === null || $fragment === '')
- {
- $this->fragment = null;
- }
- else
- {
- $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?');
- }
- $this->valid[__FUNCTION__] = true;
- return true;
- }
-
- /**
- * Get the complete IRI
- *
- * @access public
- * @return string
- */
- function get_iri()
- {
- $iri = '';
- if ($this->scheme !== null)
- {
- $iri .= $this->scheme . ':';
- }
- if (($authority = $this->get_authority()) !== null)
- {
- $iri .= '//' . $authority;
- }
- if ($this->path !== null)
- {
- $iri .= $this->path;
- }
- if ($this->query !== null)
- {
- $iri .= '?' . $this->query;
- }
- if ($this->fragment !== null)
- {
- $iri .= '#' . $this->fragment;
- }
-
- if ($iri !== '')
- {
- return $iri;
- }
- else
- {
- return null;
- }
- }
-
- /**
- * Get the scheme
- *
- * @access public
- * @return string
- */
- function get_scheme()
- {
- return $this->scheme;
- }
-
- /**
- * Get the complete authority
- *
- * @access public
- * @return string
- */
- function get_authority()
- {
- $authority = '';
- if ($this->userinfo !== null)
- {
- $authority .= $this->userinfo . '@';
- }
- if ($this->host !== null)
- {
- $authority .= $this->host;
- }
- if ($this->port !== null)
- {
- $authority .= ':' . $this->port;
- }
-
- if ($authority !== '')
- {
- return $authority;
- }
- else
- {
- return null;
- }
- }
-
- /**
- * Get the user information
- *
- * @access public
- * @return string
- */
- function get_userinfo()
- {
- return $this->userinfo;
- }
-
- /**
- * Get the host
- *
- * @access public
- * @return string
- */
- function get_host()
- {
- return $this->host;
- }
-
- /**
- * Get the port
- *
- * @access public
- * @return string
- */
- function get_port()
- {
- return $this->port;
- }
-
- /**
- * Get the path
- *
- * @access public
- * @return string
- */
- function get_path()
- {
- return $this->path;
- }
-
- /**
- * Get the query
- *
- * @access public
- * @return string
- */
- function get_query()
- {
- return $this->query;
- }
-
- /**
- * Get the fragment
- *
- * @access public
- * @return string
- */
- function get_fragment()
- {
- return $this->fragment;
+ // No-op
}
}
@@ -12608,6 +14465,7 @@ class SimplePie_IRI
* Class to validate and to work with IPv6 addresses.
*
* @package SimplePie
+ * @subpackage HTTP
* @copyright 2003-2005 The PHP Group
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/package/Net_IPv6
@@ -12619,48 +14477,28 @@ class SimplePie_IRI
class SimplePie_Net_IPv6
{
/**
- * Removes a possible existing netmask specification of an IP address.
- *
- * @param string $ip the (compressed) IP as Hex representation
- * @return string the IP the without netmask
- * @since 1.1.0
- * @access public
- * @static
- */
- function removeNetmaskSpec($ip)
- {
- if (strpos($ip, '/') !== false)
- {
- list($addr, $nm) = explode('/', $ip);
- }
- else
- {
- $addr = $ip;
- }
- return $addr;
- }
-
- /**
* Uncompresses an IPv6 address
*
- * RFC 2373 allows you to compress zeros in an address to '::'. This
- * function expects an valid IPv6 address and expands the '::' to
- * the required zeros.
+ * RFC 4291 allows you to compress concecutive zero pieces in an address to
+ * '::'. This method expects a valid IPv6 address and expands the '::' to
+ * the required number of zero pieces.
*
- * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
- * ::1 -> 0:0:0:0:0:0:0:1
+ * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
+ * ::1 -> 0:0:0:0:0:0:0:1
*
- * @access public
- * @static
- * @param string $ip a valid IPv6-address (hex format)
- * @return string the uncompressed IPv6-address (hex format)
+ * @author Alexander Merz <alexander.merz@web.de>
+ * @author elfrink at introweb dot nl
+ * @author Josh Peck <jmp at joshpeck dot org>
+ * @copyright 2003-2005 The PHP Group
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @param string $ip An IPv6 address
+ * @return string The uncompressed IPv6 address
*/
- function Uncompress($ip)
+ public static function uncompress($ip)
{
- $uip = SimplePie_Net_IPv6::removeNetmaskSpec($ip);
$c1 = -1;
$c2 = -1;
- if (strpos($ip, '::') !== false)
+ if (substr_count($ip, '::') === 1)
{
list($ip1, $ip2) = explode('::', $ip);
if ($ip1 === '')
@@ -12669,15 +14507,7 @@ class SimplePie_Net_IPv6
}
else
{
- $pos = 0;
- if (($pos = substr_count($ip1, ':')) > 0)
- {
- $c1 = $pos;
- }
- else
- {
- $c1 = 0;
- }
+ $c1 = substr_count($ip1, ':');
}
if ($ip2 === '')
{
@@ -12685,71 +14515,109 @@ class SimplePie_Net_IPv6
}
else
{
- $pos = 0;
- if (($pos = substr_count($ip2, ':')) > 0)
- {
- $c2 = $pos;
- }
- else
- {
- $c2 = 0;
- }
+ $c2 = substr_count($ip2, ':');
}
- if (strstr($ip2, '.'))
+ if (strpos($ip2, '.') !== false)
{
$c2++;
}
// ::
if ($c1 === -1 && $c2 === -1)
{
- $uip = '0:0:0:0:0:0:0:0';
+ $ip = '0:0:0:0:0:0:0:0';
}
// ::xxx
else if ($c1 === -1)
{
$fill = str_repeat('0:', 7 - $c2);
- $uip = str_replace('::', $fill, $uip);
+ $ip = str_replace('::', $fill, $ip);
}
// xxx::
else if ($c2 === -1)
{
$fill = str_repeat(':0', 7 - $c1);
- $uip = str_replace('::', $fill, $uip);
+ $ip = str_replace('::', $fill, $ip);
}
// xxx::xxx
else
{
- $fill = str_repeat(':0:', 6 - $c2 - $c1);
- $uip = str_replace('::', $fill, $uip);
- $uip = str_replace('::', ':', $uip);
+ $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
+ $ip = str_replace('::', $fill, $ip);
}
}
- return $uip;
+ return $ip;
}
/**
- * Splits an IPv6 address into the IPv6 and a possible IPv4 part
+ * Compresses an IPv6 address
*
- * RFC 2373 allows you to note the last two parts of an IPv6 address as
- * an IPv4 compatible address
+ * RFC 4291 allows you to compress concecutive zero pieces in an address to
+ * '::'. This method expects a valid IPv6 address and compresses consecutive
+ * zero pieces to '::'.
*
- * Example: 0:0:0:0:0:0:13.1.68.3
- * 0:0:0:0:0:FFFF:129.144.52.38
+ * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
+ * 0:0:0:0:0:0:0:1 -> ::1
*
- * @access public
- * @static
- * @param string $ip a valid IPv6-address (hex format)
- * @return array [0] contains the IPv6 part, [1] the IPv4 part (hex format)
+ * @see uncompress()
+ * @param string $ip An IPv6 address
+ * @return string The compressed IPv6 address
+ */
+ public static function compress($ip)
+ {
+ // Prepare the IP to be compressed
+ $ip = self::uncompress($ip);
+ $ip_parts = self::split_v6_v4($ip);
+
+ // Replace all leading zeros
+ $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
+
+ // Find bunches of zeros
+ if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
+ {
+ $max = 0;
+ $pos = null;
+ foreach ($matches[0] as $match)
+ {
+ if (strlen($match[0]) > $max)
+ {
+ $max = strlen($match[0]);
+ $pos = $match[1];
+ }
+ }
+
+ $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
+ }
+
+ if ($ip_parts[1] !== '')
+ {
+ return implode(':', $ip_parts);
+ }
+ else
+ {
+ return $ip_parts[0];
+ }
+ }
+
+ /**
+ * Splits an IPv6 address into the IPv6 and IPv4 representation parts
+ *
+ * RFC 4291 allows you to represent the last two parts of an IPv6 address
+ * using the standard IPv4 representation
+ *
+ * Example: 0:0:0:0:0:0:13.1.68.3
+ * 0:0:0:0:0:FFFF:129.144.52.38
+ *
+ * @param string $ip An IPv6 address
+ * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
*/
- function SplitV64($ip)
+ private static function split_v6_v4($ip)
{
- $ip = SimplePie_Net_IPv6::Uncompress($ip);
- if (strstr($ip, '.'))
+ if (strpos($ip, '.') !== false)
{
$pos = strrpos($ip, ':');
- $ip[$pos] = '_';
- $ipPart = explode('_', $ip);
- return $ipPart;
+ $ipv6_part = substr($ip, 0, $pos);
+ $ipv4_part = substr($ip, $pos + 1);
+ return array($ipv6_part, $ipv4_part);
}
else
{
@@ -12760,66 +14628,76 @@ class SimplePie_Net_IPv6
/**
* Checks an IPv6 address
*
- * Checks if the given IP is IPv6-compatible
+ * Checks if the given IP is a valid IPv6 address
*
- * @access public
- * @static
- * @param string $ip a valid IPv6-address
- * @return bool true if $ip is an IPv6 address
+ * @param string $ip An IPv6 address
+ * @return bool true if $ip is a valid IPv6 address
*/
- function checkIPv6($ip)
+ public static function check_ipv6($ip)
{
- $ipPart = SimplePie_Net_IPv6::SplitV64($ip);
- $count = 0;
- if (!empty($ipPart[0]))
+ $ip = self::uncompress($ip);
+ list($ipv6, $ipv4) = self::split_v6_v4($ip);
+ $ipv6 = explode(':', $ipv6);
+ $ipv4 = explode('.', $ipv4);
+ if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
{
- $ipv6 = explode(':', $ipPart[0]);
- for ($i = 0; $i < count($ipv6); $i++)
+ foreach ($ipv6 as $ipv6_part)
{
- $dec = hexdec($ipv6[$i]);
- $hex = strtoupper(preg_replace('/^[0]{1,3}(.*[0-9a-fA-F])$/', '\\1', $ipv6[$i]));
- if ($ipv6[$i] >= 0 && $dec <= 65535 && $hex === strtoupper(dechex($dec)))
- {
- $count++;
- }
- }
- if ($count === 8)
- {
- return true;
+ // The section can't be empty
+ if ($ipv6_part === '')
+ return false;
+
+ // Nor can it be over four characters
+ if (strlen($ipv6_part) > 4)
+ return false;
+
+ // Remove leading zeros (this is safe because of the above)
+ $ipv6_part = ltrim($ipv6_part, '0');
+ if ($ipv6_part === '')
+ $ipv6_part = '0';
+
+ // Check the value is valid
+ $value = hexdec($ipv6_part);
+ if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
+ return false;
}
- elseif ($count === 6 && !empty($ipPart[1]))
+ if (count($ipv4) === 4)
{
- $ipv4 = explode('.', $ipPart[1]);
- $count = 0;
foreach ($ipv4 as $ipv4_part)
{
- if ($ipv4_part >= 0 && $ipv4_part <= 255 && preg_match('/^\d{1,3}$/', $ipv4_part))
- {
- $count++;
- }
- }
- if ($count === 4)
- {
- return true;
+ $value = (int) $ipv4_part;
+ if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
+ return false;
}
}
- else
- {
- return false;
- }
-
+ return true;
}
else
{
return false;
}
}
+
+ /**
+ * Checks if the given IP is a valid IPv6 address
+ *
+ * @codeCoverageIgnore
+ * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
+ * @see check_ipv6
+ * @param string $ip An IPv6 address
+ * @return bool true if $ip is a valid IPv6 address
+ */
+ public static function checkIPv6($ip)
+ {
+ return self::check_ipv6($ip);
+ }
}
/**
* Date Parser
*
* @package SimplePie
+ * @subpackage Parsing
*/
class SimplePie_Parse_Date
{
@@ -13311,7 +15189,7 @@ class SimplePie_Parse_Date
*
* @access private
*/
- function SimplePie_Parse_Date()
+ public function __construct()
{
$this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
$this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
@@ -13341,7 +15219,7 @@ class SimplePie_Parse_Date
*
* @access public
*/
- function get()
+ public static function get()
{
static $object;
if (!$object)
@@ -13359,7 +15237,7 @@ class SimplePie_Parse_Date
* @param string $date Date to parse
* @return int Timestamp corresponding to date string, or false on failure
*/
- function parse($date)
+ public function parse($date)
{
foreach ($this->user as $method)
{
@@ -13371,7 +15249,7 @@ class SimplePie_Parse_Date
foreach ($this->built_in as $method)
{
- if (($returned = call_user_func(array(&$this, $method), $date)) !== false)
+ if (($returned = call_user_func(array($this, $method), $date)) !== false)
{
return $returned;
}
@@ -13387,7 +15265,7 @@ class SimplePie_Parse_Date
* @access public
* @param callback $callback
*/
- function add_callback($callback)
+ public function add_callback($callback)
{
if (is_callable($callback))
{
@@ -13407,7 +15285,7 @@ class SimplePie_Parse_Date
* @access protected
* @return int Timestamp
*/
- function date_w3cdtf($date)
+ public function date_w3cdtf($date)
{
static $pcre;
if (!$pcre)
@@ -13479,7 +15357,7 @@ class SimplePie_Parse_Date
* @param string $data Data to strip comments from
* @return string Comment stripped string
*/
- function remove_rfc2822_comments($string)
+ public function remove_rfc2822_comments($string)
{
$string = (string) $string;
$position = 0;
@@ -13539,7 +15417,7 @@ class SimplePie_Parse_Date
* @access protected
* @return int Timestamp
*/
- function date_rfc2822($date)
+ public function date_rfc2822($date)
{
static $pcre;
if (!$pcre)
@@ -13632,7 +15510,7 @@ class SimplePie_Parse_Date
* @access protected
* @return int Timestamp
*/
- function date_rfc850($date)
+ public function date_rfc850($date)
{
static $pcre;
if (!$pcre)
@@ -13697,7 +15575,7 @@ class SimplePie_Parse_Date
* @access protected
* @return int Timestamp
*/
- function date_asctime($date)
+ public function date_asctime($date)
{
static $pcre;
if (!$pcre)
@@ -13739,7 +15617,7 @@ class SimplePie_Parse_Date
* @access protected
* @return int Timestamp
*/
- function date_strtotime($date)
+ public function date_strtotime($date)
{
$strtotime = strtotime($date);
if ($strtotime === -1 || $strtotime === false)
@@ -13754,855 +15632,14 @@ class SimplePie_Parse_Date
}
/**
- * Content-type sniffing
+ * Parses XML into something sane
*
- * @package SimplePie
- */
-class SimplePie_Content_Type_Sniffer
-{
- /**
- * File object
- *
- * @var SimplePie_File
- * @access private
- */
- var $file;
-
- /**
- * Create an instance of the class with the input file
- *
- * @access public
- * @param SimplePie_Content_Type_Sniffer $file Input file
- */
- function SimplePie_Content_Type_Sniffer($file)
- {
- $this->file = $file;
- }
-
- /**
- * Get the Content-Type of the specified file
- *
- * @access public
- * @return string Actual Content-Type
- */
- function get_type()
- {
- if (isset($this->file->headers['content-type']))
- {
- if (!isset($this->file->headers['content-encoding'])
- && ($this->file->headers['content-type'] === 'text/plain'
- || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
- || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'))
- {
- return $this->text_or_binary();
- }
-
- if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
- {
- $official = substr($this->file->headers['content-type'], 0, $pos);
- }
- else
- {
- $official = $this->file->headers['content-type'];
- }
- $official = strtolower($official);
-
- if ($official === 'unknown/unknown'
- || $official === 'application/unknown')
- {
- return $this->unknown();
- }
- elseif (substr($official, -4) === '+xml'
- || $official === 'text/xml'
- || $official === 'application/xml')
- {
- return $official;
- }
- elseif (substr($official, 0, 6) === 'image/')
- {
- if ($return = $this->image())
- {
- return $return;
- }
- else
- {
- return $official;
- }
- }
- elseif ($official === 'text/html')
- {
- return $this->feed_or_html();
- }
- else
- {
- return $official;
- }
- }
- else
- {
- return $this->unknown();
- }
- }
-
- /**
- * Sniff text or binary
- *
- * @access private
- * @return string Actual Content-Type
- */
- function text_or_binary()
- {
- if (substr($this->file->body, 0, 2) === "\xFE\xFF"
- || substr($this->file->body, 0, 2) === "\xFF\xFE"
- || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
- || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
- {
- return 'text/plain';
- }
- elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
- {
- return 'application/octect-stream';
- }
- else
- {
- return 'text/plain';
- }
- }
-
- /**
- * Sniff unknown
- *
- * @access private
- * @return string Actual Content-Type
- */
- function unknown()
- {
- $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
- if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
- || strtolower(substr($this->file->body, $ws, 5)) === '<html'
- || strtolower(substr($this->file->body, $ws, 7)) === '<script')
- {
- return 'text/html';
- }
- elseif (substr($this->file->body, 0, 5) === '%PDF-')
- {
- return 'application/pdf';
- }
- elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
- {
- return 'application/postscript';
- }
- elseif (substr($this->file->body, 0, 6) === 'GIF87a'
- || substr($this->file->body, 0, 6) === 'GIF89a')
- {
- return 'image/gif';
- }
- elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
- {
- return 'image/png';
- }
- elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
- {
- return 'image/jpeg';
- }
- elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
- {
- return 'image/bmp';
- }
- else
- {
- return $this->text_or_binary();
- }
- }
-
- /**
- * Sniff images
- *
- * @access private
- * @return string Actual Content-Type
- */
- function image()
- {
- if (substr($this->file->body, 0, 6) === 'GIF87a'
- || substr($this->file->body, 0, 6) === 'GIF89a')
- {
- return 'image/gif';
- }
- elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
- {
- return 'image/png';
- }
- elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
- {
- return 'image/jpeg';
- }
- elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
- {
- return 'image/bmp';
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Sniff HTML
- *
- * @access private
- * @return string Actual Content-Type
- */
- function feed_or_html()
- {
- $len = strlen($this->file->body);
- $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
-
- while ($pos < $len)
- {
- switch ($this->file->body[$pos])
- {
- case "\x09":
- case "\x0A":
- case "\x0D":
- case "\x20":
- $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
- continue 2;
-
- case '<':
- $pos++;
- break;
-
- default:
- return 'text/html';
- }
-
- if (substr($this->file->body, $pos, 3) === '!--')
- {
- $pos += 3;
- if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
- {
- $pos += 3;
- }
- else
- {
- return 'text/html';
- }
- }
- elseif (substr($this->file->body, $pos, 1) === '!')
- {
- if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
- {
- $pos++;
- }
- else
- {
- return 'text/html';
- }
- }
- elseif (substr($this->file->body, $pos, 1) === '?')
- {
- if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
- {
- $pos += 2;
- }
- else
- {
- return 'text/html';
- }
- }
- elseif (substr($this->file->body, $pos, 3) === 'rss'
- || substr($this->file->body, $pos, 7) === 'rdf:RDF')
- {
- return 'application/rss+xml';
- }
- elseif (substr($this->file->body, $pos, 4) === 'feed')
- {
- return 'application/atom+xml';
- }
- else
- {
- return 'text/html';
- }
- }
-
- return 'text/html';
- }
-}
-
-/**
- * Parses the XML Declaration
+ *
+ * This class can be overloaded with {@see SimplePie::set_parser_class()}
*
* @package SimplePie
+ * @subpackage Parsing
*/
-class SimplePie_XML_Declaration_Parser
-{
- /**
- * XML Version
- *
- * @access public
- * @var string
- */
- var $version = '1.0';
-
- /**
- * Encoding
- *
- * @access public
- * @var string
- */
- var $encoding = 'UTF-8';
-
- /**
- * Standalone
- *
- * @access public
- * @var bool
- */
- var $standalone = false;
-
- /**
- * Current state of the state machine
- *
- * @access private
- * @var string
- */
- var $state = 'before_version_name';
-
- /**
- * Input data
- *
- * @access private
- * @var string
- */
- var $data = '';
-
- /**
- * Input data length (to avoid calling strlen() everytime this is needed)
- *
- * @access private
- * @var int
- */
- var $data_length = 0;
-
- /**
- * Current position of the pointer
- *
- * @var int
- * @access private
- */
- var $position = 0;
-
- /**
- * Create an instance of the class with the input data
- *
- * @access public
- * @param string $data Input data
- */
- function SimplePie_XML_Declaration_Parser($data)
- {
- $this->data = $data;
- $this->data_length = strlen($this->data);
- }
-
- /**
- * Parse the input data
- *
- * @access public
- * @return bool true on success, false on failure
- */
- function parse()
- {
- while ($this->state && $this->state !== 'emit' && $this->has_data())
- {
- $state = $this->state;
- $this->$state();
- }
- $this->data = '';
- if ($this->state === 'emit')
- {
- return true;
- }
- else
- {
- $this->version = '';
- $this->encoding = '';
- $this->standalone = '';
- return false;
- }
- }
-
- /**
- * Check whether there is data beyond the pointer
- *
- * @access private
- * @return bool true if there is further data, false if not
- */
- function has_data()
- {
- return (bool) ($this->position < $this->data_length);
- }
-
- /**
- * Advance past any whitespace
- *
- * @return int Number of whitespace characters passed
- */
- function skip_whitespace()
- {
- $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
- $this->position += $whitespace;
- return $whitespace;
- }
-
- /**
- * Read value
- */
- function get_value()
- {
- $quote = substr($this->data, $this->position, 1);
- if ($quote === '"' || $quote === "'")
- {
- $this->position++;
- $len = strcspn($this->data, $quote, $this->position);
- if ($this->has_data())
- {
- $value = substr($this->data, $this->position, $len);
- $this->position += $len + 1;
- return $value;
- }
- }
- return false;
- }
-
- function before_version_name()
- {
- if ($this->skip_whitespace())
- {
- $this->state = 'version_name';
- }
- else
- {
- $this->state = false;
- }
- }
-
- function version_name()
- {
- if (substr($this->data, $this->position, 7) === 'version')
- {
- $this->position += 7;
- $this->skip_whitespace();
- $this->state = 'version_equals';
- }
- else
- {
- $this->state = false;
- }
- }
-
- function version_equals()
- {
- if (substr($this->data, $this->position, 1) === '=')
- {
- $this->position++;
- $this->skip_whitespace();
- $this->state = 'version_value';
- }
- else
- {
- $this->state = false;
- }
- }
-
- function version_value()
- {
- if ($this->version = $this->get_value())
- {
- $this->skip_whitespace();
- if ($this->has_data())
- {
- $this->state = 'encoding_name';
- }
- else
- {
- $this->state = 'emit';
- }
- }
- else
- {
- $this->state = false;
- }
- }
-
- function encoding_name()
- {
- if (substr($this->data, $this->position, 8) === 'encoding')
- {
- $this->position += 8;
- $this->skip_whitespace();
- $this->state = 'encoding_equals';
- }
- else
- {
- $this->state = 'standalone_name';
- }
- }
-
- function encoding_equals()
- {
- if (substr($this->data, $this->position, 1) === '=')
- {
- $this->position++;
- $this->skip_whitespace();
- $this->state = 'encoding_value';
- }
- else
- {
- $this->state = false;
- }
- }
-
- function encoding_value()
- {
- if ($this->encoding = $this->get_value())
- {
- $this->skip_whitespace();
- if ($this->has_data())
- {
- $this->state = 'standalone_name';
- }
- else
- {
- $this->state = 'emit';
- }
- }
- else
- {
- $this->state = false;
- }
- }
-
- function standalone_name()
- {
- if (substr($this->data, $this->position, 10) === 'standalone')
- {
- $this->position += 10;
- $this->skip_whitespace();
- $this->state = 'standalone_equals';
- }
- else
- {
- $this->state = false;
- }
- }
-
- function standalone_equals()
- {
- if (substr($this->data, $this->position, 1) === '=')
- {
- $this->position++;
- $this->skip_whitespace();
- $this->state = 'standalone_value';
- }
- else
- {
- $this->state = false;
- }
- }
-
- function standalone_value()
- {
- if ($standalone = $this->get_value())
- {
- switch ($standalone)
- {
- case 'yes':
- $this->standalone = true;
- break;
-
- case 'no':
- $this->standalone = false;
- break;
-
- default:
- $this->state = false;
- return;
- }
-
- $this->skip_whitespace();
- if ($this->has_data())
- {
- $this->state = false;
- }
- else
- {
- $this->state = 'emit';
- }
- }
- else
- {
- $this->state = false;
- }
- }
-}
-
-class SimplePie_Locator
-{
- var $useragent;
- var $timeout;
- var $file;
- var $local = array();
- var $elsewhere = array();
- var $file_class = 'SimplePie_File';
- var $cached_entities = array();
- var $http_base;
- var $base;
- var $base_location = 0;
- var $checked_feeds = 0;
- var $max_checked_feeds = 10;
- var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
-
- function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer')
- {
- $this->file =& $file;
- $this->file_class = $file_class;
- $this->useragent = $useragent;
- $this->timeout = $timeout;
- $this->max_checked_feeds = $max_checked_feeds;
- $this->content_type_sniffer_class = $content_type_sniffer_class;
- }
-
- function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
- {
- if ($this->is_feed($this->file))
- {
- return $this->file;
- }
-
- if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
- {
- $sniffer = new $this->content_type_sniffer_class($this->file);
- if ($sniffer->get_type() !== 'text/html')
- {
- return null;
- }
- }
-
- if ($type & ~SIMPLEPIE_LOCATOR_NONE)
- {
- $this->get_base();
- }
-
- if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
- {
- return $working[0];
- }
-
- if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
- {
- if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
- {
- return $working;
- }
-
- if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
- {
- return $working;
- }
-
- if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
- {
- return $working;
- }
-
- if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
- {
- return $working;
- }
- }
- return null;
- }
-
- function is_feed(&$file)
- {
- if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
- {
- $sniffer = new $this->content_type_sniffer_class($file);
- $sniffed = $sniffer->get_type();
- if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- function get_base()
- {
- $this->http_base = $this->file->url;
- $this->base = $this->http_base;
- $elements = SimplePie_Misc::get_element('base', $this->file->body);
- foreach ($elements as $element)
- {
- if ($element['attribs']['href']['data'] !== '')
- {
- $this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base);
- $this->base_location = $element['offset'];
- break;
- }
- }
- }
-
- function autodiscovery()
- {
- $links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body));
- $done = array();
- $feeds = array();
- foreach ($links as $link)
- {
- if ($this->checked_feeds === $this->max_checked_feeds)
- {
- break;
- }
- if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data']))
- {
- $rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data'])));
-
- if ($this->base_location < $link['offset'])
- {
- $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
- }
- else
- {
- $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
- }
-
- if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
- {
- $this->checked_feeds++;
- $feed = new $this->file_class($href, $this->timeout, 5, null, $this->useragent);
- if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
- {
- $feeds[$href] = $feed;
- }
- }
- $done[] = $href;
- }
- }
-
- if (!empty($feeds))
- {
- return array_values($feeds);
- }
- else {
- return null;
- }
- }
-
- function get_links()
- {
- $links = SimplePie_Misc::get_element('a', $this->file->body);
- foreach ($links as $link)
- {
- if (isset($link['attribs']['href']['data']))
- {
- $href = trim($link['attribs']['href']['data']);
- $parsed = SimplePie_Misc::parse_url($href);
- if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
- {
- if ($this->base_location < $link['offset'])
- {
- $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
- }
- else
- {
- $href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
- }
-
- $current = SimplePie_Misc::parse_url($this->file->url);
-
- if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
- {
- $this->local[] = $href;
- }
- else
- {
- $this->elsewhere[] = $href;
- }
- }
- }
- }
- $this->local = array_unique($this->local);
- $this->elsewhere = array_unique($this->elsewhere);
- if (!empty($this->local) || !empty($this->elsewhere))
- {
- return true;
- }
- return null;
- }
-
- function extension(&$array)
- {
- foreach ($array as $key => $value)
- {
- if ($this->checked_feeds === $this->max_checked_feeds)
- {
- break;
- }
- if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
- {
- $this->checked_feeds++;
- $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
- if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
- {
- return $feed;
- }
- else
- {
- unset($array[$key]);
- }
- }
- }
- return null;
- }
-
- function body(&$array)
- {
- foreach ($array as $key => $value)
- {
- if ($this->checked_feeds === $this->max_checked_feeds)
- {
- break;
- }
- if (preg_match('/(rss|rdf|atom|xml)/i', $value))
- {
- $this->checked_feeds++;
- $feed = new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
- if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
- {
- return $feed;
- }
- else
- {
- unset($array[$key]);
- }
- }
- }
- return null;
- }
-}
-
class SimplePie_Parser
{
var $error_code;
@@ -14620,8 +15657,14 @@ class SimplePie_Parser
var $datas = array(array());
var $current_xhtml_construct = -1;
var $encoding;
+ protected $registry;
+
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
- function parse(&$data, $encoding)
+ public function parse(&$data, $encoding)
{
// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
if (strtoupper($encoding) === 'US-ASCII')
@@ -14662,7 +15705,7 @@ class SimplePie_Parser
if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
{
- $declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
+ $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
if ($declaration->parse())
{
$data = substr($data, $pos + 2);
@@ -14781,37 +15824,37 @@ class SimplePie_Parser
}
}
- function get_error_code()
+ public function get_error_code()
{
return $this->error_code;
}
- function get_error_string()
+ public function get_error_string()
{
return $this->error_string;
}
- function get_current_line()
+ public function get_current_line()
{
return $this->current_line;
}
- function get_current_column()
+ public function get_current_column()
{
return $this->current_column;
}
- function get_current_byte()
+ public function get_current_byte()
{
return $this->current_byte;
}
- function get_data()
+ public function get_data()
{
return $this->data;
}
- function tag_open($parser, $tag, $attributes)
+ public function tag_open($parser, $tag, $attributes)
{
list($this->namespace[], $this->element[]) = $this->split_ns($tag);
@@ -14824,8 +15867,12 @@ class SimplePie_Parser
if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
{
- $this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base));
- $this->xml_base_explicit[] = true;
+ $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
+ if ($base !== false)
+ {
+ $this->xml_base[] = $base;
+ $this->xml_base_explicit[] = true;
+ }
}
else
{
@@ -14864,14 +15911,17 @@ class SimplePie_Parser
$this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
$this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml')
- || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml'))
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml')
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
{
$this->current_xhtml_construct = 0;
}
}
}
- function cdata($parser, $cdata)
+ public function cdata($parser, $cdata)
{
if ($this->current_xhtml_construct >= 0)
{
@@ -14883,7 +15933,7 @@ class SimplePie_Parser
}
}
- function tag_close($parser, $tag)
+ public function tag_close($parser, $tag)
{
if ($this->current_xhtml_construct >= 0)
{
@@ -14906,7 +15956,7 @@ class SimplePie_Parser
array_pop($this->xml_lang);
}
- function split_ns($string)
+ public function split_ns($string)
{
static $cache = array();
if (!isset($cache[$string]))
@@ -14926,7 +15976,11 @@ class SimplePie_Parser
}
// Normalize the Media RSS namespaces
- if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG)
+ if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
{
$namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
}
@@ -14942,6 +15996,392 @@ class SimplePie_Parser
}
/**
+ * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
+ *
+ * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_rating_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Rating
+{
+ /**
+ * Rating scheme
+ *
+ * @var string
+ * @see get_scheme()
+ */
+ var $scheme;
+
+ /**
+ * Rating value
+ *
+ * @var string
+ * @see get_value()
+ */
+ var $value;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($scheme = null, $value = null)
+ {
+ $this->scheme = $scheme;
+ $this->value = $value;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the organizational scheme for the rating
+ *
+ * @return string|null
+ */
+ public function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the value of the rating
+ *
+ * @return string|null
+ */
+ public function get_value()
+ {
+ if ($this->value !== null)
+ {
+ return $this->value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * Handles creating objects and calling methods
+ *
+ * Access this via {@see SimplePie::get_registry()}
+ *
+ * @package SimplePie
+ */
+class SimplePie_Registry
+{
+ /**
+ * Default class mapping
+ *
+ * Overriding classes *must* subclass these.
+ *
+ * @var array
+ */
+ protected $default = array(
+ 'Cache' => 'SimplePie_Cache',
+ 'Locator' => 'SimplePie_Locator',
+ 'Parser' => 'SimplePie_Parser',
+ 'File' => 'SimplePie_File',
+ 'Sanitize' => 'SimplePie_Sanitize',
+ 'Item' => 'SimplePie_Item',
+ 'Author' => 'SimplePie_Author',
+ 'Category' => 'SimplePie_Category',
+ 'Enclosure' => 'SimplePie_Enclosure',
+ 'Caption' => 'SimplePie_Caption',
+ 'Copyright' => 'SimplePie_Copyright',
+ 'Credit' => 'SimplePie_Credit',
+ 'Rating' => 'SimplePie_Rating',
+ 'Restriction' => 'SimplePie_Restriction',
+ 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
+ 'Source' => 'SimplePie_Source',
+ 'Misc' => 'SimplePie_Misc',
+ 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
+ 'Parse_Date' => 'SimplePie_Parse_Date',
+ );
+
+ /**
+ * Class mapping
+ *
+ * @see register()
+ * @var array
+ */
+ protected $classes = array();
+
+ /**
+ * Legacy classes
+ *
+ * @see register()
+ * @var array
+ */
+ protected $legacy = array();
+
+ /**
+ * Constructor
+ *
+ * No-op
+ */
+ public function __construct() { }
+
+ /**
+ * Register a class
+ *
+ * @param string $type See {@see $default} for names
+ * @param string $class Class name, must subclass the corresponding default
+ * @param bool $legacy Whether to enable legacy support for this class
+ * @return bool Successfulness
+ */
+ public function register($type, $class, $legacy = false)
+ {
+ if (!is_subclass_of($class, $this->default[$type]))
+ {
+ return false;
+ }
+
+ $this->classes[$type] = $class;
+
+ if ($legacy)
+ {
+ $this->legacy[] = $class;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the class registered for a type
+ *
+ * Where possible, use {@see create()} or {@see call()} instead
+ *
+ * @param string $type
+ * @return string|null
+ */
+ public function get_class($type)
+ {
+ if (!empty($this->classes[$type]))
+ {
+ return $this->classes[$type];
+ }
+ if (!empty($this->default[$type]))
+ {
+ return $this->default[$type];
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a new instance of a given type
+ *
+ * @param string $type
+ * @param array $parameters Parameters to pass to the constructor
+ * @return object Instance of class
+ */
+ public function &create($type, $parameters = array())
+ {
+ $class = $this->get_class($type);
+
+ if (in_array($class, $this->legacy))
+ {
+ switch ($type)
+ {
+ case 'locator':
+ // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
+ // Specified: file, timeout, useragent, max_checked_feeds
+ $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
+ array_splice($parameters, 3, 1, $replacement);
+ break;
+ }
+ }
+
+ if (!method_exists($class, '__construct'))
+ {
+ $instance = new $class;
+ }
+ else
+ {
+ $reflector = new ReflectionClass($class);
+ $instance = $reflector->newInstanceArgs($parameters);
+ }
+
+ if (method_exists($instance, 'set_registry'))
+ {
+ $instance->set_registry($this);
+ }
+ return $instance;
+ }
+
+ /**
+ * Call a static method for a type
+ *
+ * @param string $type
+ * @param string $method
+ * @param array $parameters
+ * @return mixed
+ */
+ public function &call($type, $method, $parameters = array())
+ {
+ $class = $this->get_class($type);
+
+ if (in_array($class, $this->legacy))
+ {
+ switch ($type)
+ {
+ case 'Cache':
+ // For backwards compatibility with old non-static
+ // Cache::create() methods
+ if ($method === 'get_handler')
+ {
+ $result = @call_user_func_array(array($class, 'create'), $parameters);
+ return $result;
+ }
+ break;
+ }
+ }
+
+ $result = call_user_func_array(array($class, $method), $parameters);
+ return $result;
+ }
+}
+
+/**
+ * Handles `<media:restriction>` as defined in Media RSS
+ *
+ * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_restriction_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Restriction
+{
+ /**
+ * Relationship ('allow'/'deny')
+ *
+ * @var string
+ * @see get_relationship()
+ */
+ var $relationship;
+
+ /**
+ * Type of restriction
+ *
+ * @var string
+ * @see get_type()
+ */
+ var $type;
+
+ /**
+ * Restricted values
+ *
+ * @var string
+ * @see get_value()
+ */
+ var $value;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($relationship = null, $type = null, $value = null)
+ {
+ $this->relationship = $relationship;
+ $this->type = $type;
+ $this->value = $value;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the relationship
+ *
+ * @return string|null Either 'allow' or 'deny'
+ */
+ public function get_relationship()
+ {
+ if ($this->relationship !== null)
+ {
+ return $this->relationship;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the type
+ *
+ * @return string|null
+ */
+ public function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the list of restricted things
+ *
+ * @return string|null
+ */
+ public function get_value()
+ {
+ if ($this->value !== null)
+ {
+ return $this->value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * Used for data cleanup and post-processing
+ *
+ *
+ * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
+ *
+ * @package SimplePie
* @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
*/
class SimplePie_Sanitize
@@ -14960,30 +16400,23 @@ class SimplePie_Sanitize
var $enable_cache = true;
var $cache_location = './cache';
var $cache_name_function = 'md5';
- var $cache_class = 'SimplePie_Cache';
- var $file_class = 'SimplePie_File';
var $timeout = 10;
var $useragent = '';
var $force_fsockopen = false;
+ var $replace_url_attributes = null;
- var $replace_url_attributes = array(
- 'a' => 'href',
- 'area' => 'href',
- 'blockquote' => 'cite',
- 'del' => 'cite',
- 'form' => 'action',
- 'img' => array('longdesc', 'src'),
- 'input' => 'src',
- 'ins' => 'cite',
- 'q' => 'cite'
- );
+ public function __construct()
+ {
+ // Set defaults
+ $this->set_url_replacements(null);
+ }
- function remove_div($enable = true)
+ public function remove_div($enable = true)
{
$this->remove_div = (bool) $enable;
}
- function set_image_handler($page = false)
+ public function set_image_handler($page = false)
{
if ($page)
{
@@ -14995,7 +16428,12 @@ class SimplePie_Sanitize
}
}
- function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
{
if (isset($enable_cache))
{
@@ -15011,20 +16449,10 @@ class SimplePie_Sanitize
{
$this->cache_name_function = (string) $cache_name_function;
}
-
- if ($cache_class)
- {
- $this->cache_class = (string) $cache_class;
- }
}
- function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
+ public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
{
- if ($file_class)
- {
- $this->file_class = (string) $file_class;
- }
-
if ($timeout)
{
$this->timeout = (string) $timeout;
@@ -15041,7 +16469,7 @@ class SimplePie_Sanitize
}
}
- function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
+ public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
{
if ($tags)
{
@@ -15060,12 +16488,12 @@ class SimplePie_Sanitize
}
}
- function encode_instead_of_strip($encode = false)
+ public function encode_instead_of_strip($encode = false)
{
$this->encode_instead_of_strip = (bool) $encode;
}
- function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
+ public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
{
if ($attribs)
{
@@ -15084,12 +16512,12 @@ class SimplePie_Sanitize
}
}
- function strip_comments($strip = false)
+ public function strip_comments($strip = false)
{
$this->strip_comments = (bool) $strip;
}
- function set_output_encoding($encoding = 'UTF-8')
+ public function set_output_encoding($encoding = 'UTF-8')
{
$this->output_encoding = (string) $encoding;
}
@@ -15098,16 +16526,36 @@ class SimplePie_Sanitize
* Set element/attribute key/value pairs of HTML attributes
* containing URLs that need to be resolved relative to the feed
*
- * @access public
+ * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
+ * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
+ * |q|@cite
+ *
* @since 1.0
- * @param array $element_attribute Element/attribute key/value pairs
+ * @param array|null $element_attribute Element/attribute key/value pairs, null for default
*/
- function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
- {
+ public function set_url_replacements($element_attribute = null)
+ {
+ if ($element_attribute === null)
+ {
+ $element_attribute = array(
+ 'a' => 'href',
+ 'area' => 'href',
+ 'blockquote' => 'cite',
+ 'del' => 'cite',
+ 'form' => 'action',
+ 'img' => array(
+ 'longdesc',
+ 'src'
+ ),
+ 'input' => 'src',
+ 'ins' => 'cite',
+ 'q' => 'cite'
+ );
+ }
$this->replace_url_attributes = (array) $element_attribute;
}
- function sanitize($data, $type, $base = '')
+ public function sanitize($data, $type, $base = '')
{
$data = trim($data);
if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
@@ -15129,25 +16577,27 @@ class SimplePie_Sanitize
$data = base64_decode($data);
}
- if ($type & SIMPLEPIE_CONSTRUCT_XHTML)
- {
- if ($this->remove_div)
- {
- $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
- $data = preg_replace('/<\/div>$/', '', $data);
- }
- else
- {
- $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
- }
- }
-
if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
{
+
+ $document = new DOMDocument();
+ $document->encoding = 'UTF-8';
+ $data = $this->preprocess($data, $type);
+
+ set_error_handler(array('SimplePie_Misc', 'silence_errors'));
+ $document->loadHTML($data);
+ restore_error_handler();
+
// Strip comments
if ($this->strip_comments)
{
- $data = SimplePie_Misc::strip_comments($data);
+ $xpath = new DOMXPath($document);
+ $comments = $xpath->query('//comment()');
+
+ foreach ($comments as $comment)
+ {
+ $comment->parentNode->removeChild($comment);
+ }
}
// Strip out HTML tags and attributes that might cause various security problems.
@@ -15157,11 +16607,7 @@ class SimplePie_Sanitize
{
foreach ($this->strip_htmltags as $tag)
{
- $pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU';
- while (preg_match($pcre, $data))
- {
- $data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data);
- }
+ $this->strip_tag($tag, $document, $type);
}
}
@@ -15169,7 +16615,7 @@ class SimplePie_Sanitize
{
foreach ($this->strip_attributes as $attrib)
{
- $data = preg_replace('/(<[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . trim($attrib) . '(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>/', '\1\2\3>', $data);
+ $this->strip_attr($attrib, $document);
}
}
@@ -15177,36 +16623,34 @@ class SimplePie_Sanitize
$this->base = $base;
foreach ($this->replace_url_attributes as $element => $attributes)
{
- $data = $this->replace_urls($data, $element, $attributes);
+ $this->replace_urls($document, $element, $attributes);
}
// If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
{
- $images = SimplePie_Misc::get_element('img', $data);
+ $images = $document->getElementsByTagName('img');
foreach ($images as $img)
{
- if (isset($img['attribs']['src']['data']))
+ if ($img->hasAttribute('src'))
{
- $image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']);
- $cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi');
+ $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
+ $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
if ($cache->load())
{
- $img['attribs']['src']['data'] = $this->image_handler . $image_url;
- $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
+ $img->setAttribute('src', $this->image_handler . $image_url);
}
else
{
- $file = new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
+ $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
$headers = $file->headers;
if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
{
if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
{
- $img['attribs']['src']['data'] = $this->image_handler . $image_url;
- $data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
+ $img->setAttribute('src', $this->image_handler . $image_url);
}
else
{
@@ -15218,13 +16662,38 @@ class SimplePie_Sanitize
}
}
- // Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data
- $data = trim($data);
+ // Remove the DOCTYPE
+ // Seems to cause segfaulting if we don't do this
+ if ($document->firstChild instanceof DOMDocumentType)
+ {
+ $document->removeChild($document->firstChild);
+ }
+
+ // Move everything from the body to the root
+ $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
+ $document->replaceChild($real_body, $document->firstChild);
+
+ // Finally, convert to a HTML string
+ $data = trim($document->saveHTML());
+
+ if ($this->remove_div)
+ {
+ $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
+ $data = preg_replace('/<\/div>$/', '', $data);
+ }
+ else
+ {
+ $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
+ }
}
if ($type & SIMPLEPIE_CONSTRUCT_IRI)
{
- $data = SimplePie_Misc::absolutize_url($data, $base);
+ $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
+ if ($absolute !== false)
+ {
+ $data = $absolute;
+ }
}
if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
@@ -15234,43 +16703,63 @@ class SimplePie_Sanitize
if ($this->output_encoding !== 'UTF-8')
{
- $data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding);
+ $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
}
}
return $data;
}
- function replace_urls($data, $tag, $attributes)
+ protected function preprocess($html, $type)
{
+ $ret = '';
+ if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
+ {
+ // Atom XHTML constructs are wrapped with a div by default
+ // Note: No protection if $html contains a stray </div>!
+ $html = '<div>' . $html . '</div>';
+ $ret .= '<!DOCTYPE html>';
+ $content_type = 'text/html';
+ }
+ else
+ {
+ $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
+ $content_type = 'application/xhtml+xml';
+ }
+
+ $ret .= '<html><head>';
+ $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
+ $ret .= '</head><body>' . $html . '</body></html>';
+ return $ret;
+ }
+
+ public function replace_urls($document, $tag, $attributes)
+ {
+ if (!is_array($attributes))
+ {
+ $attributes = array($attributes);
+ }
+
if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
{
- $elements = SimplePie_Misc::get_element($tag, $data);
+ $elements = $document->getElementsByTagName($tag);
foreach ($elements as $element)
{
- if (is_array($attributes))
+ foreach ($attributes as $attribute)
{
- foreach ($attributes as $attribute)
+ if ($element->hasAttribute($attribute))
{
- if (isset($element['attribs'][$attribute]['data']))
+ $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
+ if ($value !== false)
{
- $element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base);
- $new_element = SimplePie_Misc::element_implode($element);
- $data = str_replace($element['full'], $new_element, $data);
- $element['full'] = $new_element;
+ $element->setAttribute($attribute, $value);
}
}
}
- elseif (isset($element['attribs'][$attributes]['data']))
- {
- $element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base);
- $data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data);
- }
}
}
- return $data;
}
- function do_strip_htmltags($match)
+ public function do_strip_htmltags($match)
{
if ($this->encode_instead_of_strip)
{
@@ -15294,6 +16783,986 @@ class SimplePie_Sanitize
return '';
}
}
+
+ protected function strip_tag($tag, $document, $type)
+ {
+ $xpath = new DOMXPath($document);
+ $elements = $xpath->query('body//' . $tag);
+ if ($this->encode_instead_of_strip)
+ {
+ foreach ($elements as $element)
+ {
+ $fragment = $document->createDocumentFragment();
+
+ // For elements which aren't script or style, include the tag itself
+ if (!in_array($tag, array('script', 'style')))
+ {
+ $text = '<' . $tag;
+ if ($element->hasAttributes())
+ {
+ $attrs = array();
+ foreach ($element->attributes as $name => $attr)
+ {
+ $value = $attr->value;
+
+ // In XHTML, empty values should never exist, so we repeat the value
+ if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
+ {
+ $value = $name;
+ }
+ // For HTML, empty is fine
+ elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
+ {
+ $attrs[] = $name;
+ continue;
+ }
+
+ // Standard attribute text
+ $attrs[] = $name . '="' . $attr->value . '"';
+ }
+ $text .= ' ' . implode(' ', $attrs);
+ }
+ $text .= '>';
+ $fragment->appendChild(new DOMText($text));
+ }
+
+ $number = $element->childNodes->length;
+ for ($i = $number; $i > 0; $i--)
+ {
+ $child = $element->childNodes->item(0);
+ $fragment->appendChild($child);
+ }
+
+ if (!in_array($tag, array('script', 'style')))
+ {
+ $fragment->appendChild(new DOMText('</' . $tag . '>'));
+ }
+
+ $element->parentNode->replaceChild($fragment, $element);
+ }
+
+ return;
+ }
+ elseif (in_array($tag, array('script', 'style')))
+ {
+ foreach ($elements as $element)
+ {
+ $element->parentNode->removeChild($element);
+ }
+
+ return;
+ }
+ else
+ {
+ foreach ($elements as $element)
+ {
+ $fragment = $document->createDocumentFragment();
+ $number = $element->childNodes->length;
+ for ($i = $number; $i > 0; $i--)
+ {
+ $child = $element->childNodes->item(0);
+ $fragment->appendChild($child);
+ }
+
+ $element->parentNode->replaceChild($fragment, $element);
+ }
+ }
+ }
+
+ protected function strip_attr($attrib, $document)
+ {
+ $xpath = new DOMXPath($document);
+ $elements = $xpath->query('//*[@' . $attrib . ']');
+
+ foreach ($elements as $element)
+ {
+ $element->removeAttribute($attrib);
+ }
+ }
+}
+
+/**
+ * Handles `<atom:source>`
+ *
+ * Used by {@see SimplePie_Item::get_source()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_source_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Source
+{
+ var $item;
+ var $data = array();
+ protected $registry;
+
+ public function __construct($item, $data)
+ {
+ $this->item = $item;
+ $this->data = $data;
+ }
+
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ public function __toString()
+ {
+ return md5(serialize($this->data));
+ }
+
+ public function get_source_tags($namespace, $tag)
+ {
+ if (isset($this->data['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][$namespace][$tag];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_base($element = array())
+ {
+ return $this->item->get_base($element);
+ }
+
+ public function sanitize($data, $type, $base = '')
+ {
+ return $this->item->sanitize($data, $type, $base);
+ }
+
+ public function get_item()
+ {
+ return $this->item;
+ }
+
+ public function get_title()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_categories()
+ {
+ $categories = array();
+
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['attribs']['']['term']))
+ {
+ $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
+ {
+ // This is really the label, but keep this as the term also for BC.
+ // Label will also work on retrieving because that falls back to term.
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ if (isset($category['attribs']['']['domain']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = null;
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($categories))
+ {
+ return array_unique($categories);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_author($key = 0)
+ {
+ $authors = $this->get_authors();
+ if (isset($authors[$key]))
+ {
+ return $authors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_authors()
+ {
+ $authors = array();
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($authors))
+ {
+ return array_unique($authors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_contributor($key = 0)
+ {
+ $contributors = $this->get_contributors();
+ if (isset($contributors[$key]))
+ {
+ return $contributors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_contributors()
+ {
+ $contributors = array();
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+
+ if (!empty($contributors))
+ {
+ return array_unique($contributors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_link($key = 0, $rel = 'alternate')
+ {
+ $links = $this->get_links($rel);
+ if (isset($links[$key]))
+ {
+ return $links[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Added for parity between the parent-level and the item/entry-level.
+ */
+ public function get_permalink()
+ {
+ return $this->get_link(0);
+ }
+
+ public function get_links($rel = 'alternate')
+ {
+ if (!isset($this->data['links']))
+ {
+ $this->data['links'] = array();
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ }
+ }
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+ }
+ }
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+
+ $keys = array_keys($this->data['links']);
+ foreach ($keys as $key)
+ {
+ if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
+ {
+ if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+ $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+ }
+ else
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+ }
+ }
+ elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+ {
+ $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+ }
+ $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ }
+ }
+
+ if (isset($this->data['links'][$rel]))
+ {
+ return $this->data['links'][$rel];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_description()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_copyright()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_language()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['xml_lang']))
+ {
+ return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_latitude()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[1];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_longitude()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[2];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_image_url()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
+ {
+ return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
+/**
+ * Parses the XML Declaration
+ *
+ * @package SimplePie
+ * @subpackage Parsing
+ */
+class SimplePie_XML_Declaration_Parser
+{
+ /**
+ * XML Version
+ *
+ * @access public
+ * @var string
+ */
+ var $version = '1.0';
+
+ /**
+ * Encoding
+ *
+ * @access public
+ * @var string
+ */
+ var $encoding = 'UTF-8';
+
+ /**
+ * Standalone
+ *
+ * @access public
+ * @var bool
+ */
+ var $standalone = false;
+
+ /**
+ * Current state of the state machine
+ *
+ * @access private
+ * @var string
+ */
+ var $state = 'before_version_name';
+
+ /**
+ * Input data
+ *
+ * @access private
+ * @var string
+ */
+ var $data = '';
+
+ /**
+ * Input data length (to avoid calling strlen() everytime this is needed)
+ *
+ * @access private
+ * @var int
+ */
+ var $data_length = 0;
+
+ /**
+ * Current position of the pointer
+ *
+ * @var int
+ * @access private
+ */
+ var $position = 0;
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @access public
+ * @param string $data Input data
+ */
+ public function __construct($data)
+ {
+ $this->data = $data;
+ $this->data_length = strlen($this->data);
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @access public
+ * @return bool true on success, false on failure
+ */
+ public function parse()
+ {
+ while ($this->state && $this->state !== 'emit' && $this->has_data())
+ {
+ $state = $this->state;
+ $this->$state();
+ }
+ $this->data = '';
+ if ($this->state === 'emit')
+ {
+ return true;
+ }
+ else
+ {
+ $this->version = '';
+ $this->encoding = '';
+ $this->standalone = '';
+ return false;
+ }
+ }
+
+ /**
+ * Check whether there is data beyond the pointer
+ *
+ * @access private
+ * @return bool true if there is further data, false if not
+ */
+ public function has_data()
+ {
+ return (bool) ($this->position < $this->data_length);
+ }
+
+ /**
+ * Advance past any whitespace
+ *
+ * @return int Number of whitespace characters passed
+ */
+ public function skip_whitespace()
+ {
+ $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
+ $this->position += $whitespace;
+ return $whitespace;
+ }
+
+ /**
+ * Read value
+ */
+ public function get_value()
+ {
+ $quote = substr($this->data, $this->position, 1);
+ if ($quote === '"' || $quote === "'")
+ {
+ $this->position++;
+ $len = strcspn($this->data, $quote, $this->position);
+ if ($this->has_data())
+ {
+ $value = substr($this->data, $this->position, $len);
+ $this->position += $len + 1;
+ return $value;
+ }
+ }
+ return false;
+ }
+
+ public function before_version_name()
+ {
+ if ($this->skip_whitespace())
+ {
+ $this->state = 'version_name';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function version_name()
+ {
+ if (substr($this->data, $this->position, 7) === 'version')
+ {
+ $this->position += 7;
+ $this->skip_whitespace();
+ $this->state = 'version_equals';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function version_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'version_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function version_value()
+ {
+ if ($this->version = $this->get_value())
+ {
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = 'encoding_name';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function encoding_name()
+ {
+ if (substr($this->data, $this->position, 8) === 'encoding')
+ {
+ $this->position += 8;
+ $this->skip_whitespace();
+ $this->state = 'encoding_equals';
+ }
+ else
+ {
+ $this->state = 'standalone_name';
+ }
+ }
+
+ public function encoding_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'encoding_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function encoding_value()
+ {
+ if ($this->encoding = $this->get_value())
+ {
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = 'standalone_name';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function standalone_name()
+ {
+ if (substr($this->data, $this->position, 10) === 'standalone')
+ {
+ $this->position += 10;
+ $this->skip_whitespace();
+ $this->state = 'standalone_equals';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function standalone_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'standalone_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function standalone_value()
+ {
+ if ($standalone = $this->get_value())
+ {
+ switch ($standalone)
+ {
+ case 'yes':
+ $this->standalone = true;
+ break;
+
+ case 'no':
+ $this->standalone = false;
+ break;
+
+ default:
+ $this->state = false;
+ return;
+ }
+
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = false;
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
}
-?>
diff --git a/inc/Tar.class.php b/inc/Tar.class.php
new file mode 100644
index 000000000..20f397395
--- /dev/null
+++ b/inc/Tar.class.php
@@ -0,0 +1,634 @@
+<?php
+/**
+ * This class allows the extraction of existing and the creation of new Unix TAR archives.
+ * To keep things simple, the modification of existing archives is not supported. It handles
+ * uncompressed, gzip and bzip2 compressed tar files.
+ *
+ * Long pathnames (>100 chars) are supported in POSIX ustar and GNU longlink formats.
+ *
+ * To list the contents of an existing TAR archive, open() it and use contents() on it:
+ *
+ * $tar = new Tar();
+ * $tar->open('myfile.tgz');
+ * $toc = $tar->contents();
+ * print_r($toc);
+ *
+ * To extract the contents of an existing TAR archive, open() it and use extract() on it:
+ *
+ * $tar = new Tar();
+ * $tar->open('myfile.tgz');
+ * $tar->extract('/tmp');
+ *
+ * To create a new TAR archive directly on the filesystem (low memory requirements), create() it,
+ * add*() files and close() it:
+ *
+ * $tar = new Tar();
+ * $tar->create('myfile.tgz');
+ * $tar->addFile(...);
+ * $tar->addData(...);
+ * ...
+ * $tar->close();
+ *
+ * To create a TAR archive directly in memory, create() it, add*() files and then either save()
+ * or getData() it:
+ *
+ * $tar = new Tar();
+ * $tar->create();
+ * $tar->addFile(...);
+ * $tar->addData(...);
+ * ...
+ * $tar->save('myfile.tgz'); // compresses and saves it
+ * echo $tar->getArchive(Tar::COMPRESS_GZIP); // compresses and returns it
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Bouchon <tarlib@bouchon.org> (Maxg)
+ * @license GPL 2
+ */
+class Tar {
+
+ const COMPRESS_AUTO = 0;
+ const COMPRESS_NONE = 1;
+ const COMPRESS_GZIP = 2;
+ const COMPRESS_BZIP = 3;
+
+ protected $file = '';
+ protected $comptype = Tar::COMPRESS_AUTO;
+ protected $fh;
+ protected $memory = '';
+ protected $closed = true;
+ protected $writeaccess = false;
+
+ /**
+ * Open an existing TAR file for reading
+ *
+ * @param string $file
+ * @param int $comptype
+ * @throws TarIOException
+ */
+ public function open($file, $comptype = Tar::COMPRESS_AUTO) {
+ // determine compression
+ if($comptype == Tar::COMPRESS_AUTO) $comptype = $this->filetype($file);
+ $this->compressioncheck($comptype);
+
+ $this->comptype = $comptype;
+ $this->file = $file;
+
+ if($this->comptype === Tar::COMPRESS_GZIP) {
+ $this->fh = @gzopen($this->file, 'rb');
+ } elseif($this->comptype === Tar::COMPRESS_BZIP) {
+ $this->fh = @bzopen($this->file, 'r');
+ } else {
+ $this->fh = @fopen($this->file, 'rb');
+ }
+
+ if(!$this->fh) throw new TarIOException('Could not open file for reading: '.$this->file);
+ $this->closed = false;
+ }
+
+ /**
+ * Read the contents of a TAR archive
+ *
+ * This function lists the files stored in the archive, and returns an indexed array of associative
+ * arrays containing for each file the following information:
+ *
+ * checksum Tar Checksum of the file
+ * filename The full name of the stored file (up to 100 c.)
+ * mode UNIX permissions in DECIMAL, not octal
+ * uid The Owner ID
+ * gid The Group ID
+ * size Uncompressed filesize
+ * mtime Timestamp of last modification
+ * typeflag Empty for files, set for folders
+ * link Is it a symlink?
+ * uname Owner name
+ * gname Group name
+ *
+ * The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
+ * Reopen the file with open() again if you want to do additional operations
+ */
+ public function contents() {
+ if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive');
+
+ $result = array();
+ while($read = $this->readbytes(512)) {
+ $header = $this->parseHeader($read);
+ if(!is_array($header)) continue;
+
+ $this->skipbytes(ceil($header['size'] / 512) * 512, 1);
+ $result[] = $header;
+ }
+
+ $this->close();
+ return $result;
+ }
+
+ /**
+ * Extract an existing TAR archive
+ *
+ * The $strip parameter allows you to strip a certain number of path components from the filenames
+ * found in the tar file, similar to the --strip-components feature of GNU tar. This is triggered when
+ * an integer is passed as $strip.
+ * Alternatively a fixed string prefix may be passed in $strip. If the filename matches this prefix,
+ * the prefix will be stripped. It is recommended to give prefixes with a trailing slash.
+ *
+ * By default this will extract all files found in the archive. You can restrict the output using the $include
+ * and $exclude parameter. Both expect a full regular expression (including delimiters and modifiers). If
+ * $include is set only files that match this expression will be extracted. Files that match the $exclude
+ * expression will never be extracted. Both parameters can be used in combination. Expressions are matched against
+ * stripped filenames as described above.
+ *
+ * The archive is closed afer reading the contents, because rewinding is not possible in bzip2 streams.
+ * Reopen the file with open() again if you want to do additional operations
+ *
+ * @param string $outdir the target directory for extracting
+ * @param int|string $strip either the number of path components or a fixed prefix to strip
+ * @param string $exclude a regular expression of files to exclude
+ * @param string $include a regular expression of files to include
+ * @throws TarIOException
+ * @return array
+ */
+ function extract($outdir, $strip = '', $exclude = '', $include = '') {
+ if($this->closed || !$this->file) throw new TarIOException('Can not read from a closed archive');
+
+ $outdir = rtrim($outdir, '/');
+ io_mkdir_p($outdir);
+ $striplen = strlen($strip);
+
+ $extracted = array();
+
+ while($dat = $this->readbytes(512)) {
+ // read the file header
+ $header = $this->parseHeader($dat);
+ if(!is_array($header)) continue;
+ if(!$header['filename']) continue;
+
+ // strip prefix
+ $filename = $this->cleanPath($header['filename']);
+ if(is_int($strip)) {
+ // if $strip is an integer we strip this many path components
+ $parts = explode('/', $filename);
+ if(!$header['typeflag']) {
+ $base = array_pop($parts); // keep filename itself
+ } else {
+ $base = '';
+ }
+ $filename = join('/', array_slice($parts, $strip));
+ if($base) $filename .= "/$base";
+ } else {
+ // ifstrip is a string, we strip a prefix here
+ if(substr($filename, 0, $striplen) == $strip) $filename = substr($filename, $striplen);
+ }
+
+ // check if this should be extracted
+ $extract = true;
+ if(!$filename) {
+ $extract = false;
+ } else {
+ if($include) {
+ if(preg_match($include, $filename)) {
+ $extract = true;
+ } else {
+ $extract = false;
+ }
+ }
+ if($exclude && preg_match($exclude, $filename)) {
+ $extract = false;
+ }
+ }
+
+ // Now do the extraction (or not)
+ if($extract) {
+ $extracted[] = $header;
+
+ $output = "$outdir/$filename";
+ $directory = ($header['typeflag']) ? $output : dirname($output);
+ io_mkdir_p($directory);
+
+ // is this a file?
+ if(!$header['typeflag']) {
+ $fp = fopen($output, "wb");
+ if(!$fp) throw new TarIOException('Could not open file for writing: '.$output);
+
+ $size = floor($header['size'] / 512);
+ for($i = 0; $i < $size; $i++) {
+ fwrite($fp, $this->readbytes(512), 512);
+ }
+ if(($header['size'] % 512) != 0) fwrite($fp, $this->readbytes(512), $header['size'] % 512);
+
+ fclose($fp);
+ touch($output, $header['mtime']);
+ chmod($output, $header['perm']);
+ } else {
+ $this->skipbytes(ceil($header['size'] / 512) * 512); // the size is usually 0 for directories
+ }
+ } else {
+ $this->skipbytes(ceil($header['size'] / 512) * 512);
+ }
+ }
+
+ $this->close();
+ return $extracted;
+ }
+
+ /**
+ * Create a new TAR file
+ *
+ * If $file is empty, the tar file will be created in memory
+ *
+ * @param string $file
+ * @param int $comptype
+ * @param int $complevel
+ * @throws TarIOException
+ * @throws TarIllegalCompressionException
+ */
+ public function create($file = '', $comptype = Tar::COMPRESS_AUTO, $complevel = 9) {
+ // determine compression
+ if($comptype == Tar::COMPRESS_AUTO) $comptype = $this->filetype($file);
+ $this->compressioncheck($comptype);
+
+ $this->comptype = $comptype;
+ $this->file = $file;
+ $this->memory = '';
+ $this->fh = 0;
+
+ if($this->file) {
+ if($this->comptype === Tar::COMPRESS_GZIP) {
+ $this->fh = @gzopen($this->file, 'wb'.$complevel);
+ } elseif($this->comptype === Tar::COMPRESS_BZIP) {
+ $this->fh = @bzopen($this->file, 'w');
+ } else {
+ $this->fh = @fopen($this->file, 'wb');
+ }
+
+ if(!$this->fh) throw new TarIOException('Could not open file for writing: '.$this->file);
+ }
+ $this->writeaccess = false;
+ $this->closed = false;
+ }
+
+ /**
+ * Add a file to the current TAR archive using an existing file in the filesystem
+ *
+ * @todo handle directory adding
+ * @param string $file the original file
+ * @param string $name the name to use for the file in the archive
+ * @throws TarIOException
+ */
+ public function addFile($file, $name = '') {
+ if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added');
+
+ if(!$name) $name = $file;
+ $name = $this->cleanPath($name);
+
+ $fp = fopen($file, 'rb');
+ if(!$fp) throw new TarIOException('Could not open file for reading: '.$file);
+
+ // create file header and copy all stat info from the original file
+ clearstatcache(false, $file);
+ $stat = stat($file);
+ $this->writeFileHeader(
+ $name,
+ $stat[4],
+ $stat[5],
+ fileperms($file),
+ filesize($file),
+ filemtime($file)
+ );
+
+ while(!feof($fp)) {
+ $packed = pack("a512", fread($fp, 512));
+ $this->writebytes($packed);
+ }
+ fclose($fp);
+ }
+
+ /**
+ * Add a file to the current TAR archive using the given $data as content
+ *
+ * @param string $name
+ * @param string $data
+ * @param int $uid
+ * @param int $gid
+ * @param int $perm
+ * @param int $mtime
+ * @throws TarIOException
+ */
+ public function addData($name, $data, $uid = 0, $gid = 0, $perm = 0666, $mtime = 0) {
+ if($this->closed) throw new TarIOException('Archive has been closed, files can no longer be added');
+
+ $name = $this->cleanPath($name);
+ $len = strlen($data);
+
+ $this->writeFileHeader(
+ $name,
+ $uid,
+ $gid,
+ $perm,
+ $len,
+ ($mtime) ? $mtime : time()
+ );
+
+ for($s = 0; $s < $len; $s += 512) {
+ $this->writebytes(pack("a512", substr($data, $s, 512)));
+ }
+ }
+
+ /**
+ * Add the closing footer to the archive if in write mode, close all file handles
+ *
+ * After a call to this function no more data can be added to the archive, for
+ * read access no reading is allowed anymore
+ *
+ * "Physically, an archive consists of a series of file entries terminated by an end-of-archive entry, which
+ * consists of two 512 blocks of zero bytes"
+ *
+ * @link http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134
+ */
+ public function close() {
+ if($this->closed) return; // we did this already
+
+ // write footer
+ if($this->writeaccess) {
+ $this->writebytes(pack("a512", ""));
+ $this->writebytes(pack("a512", ""));
+ }
+
+ // close file handles
+ if($this->file) {
+ if($this->comptype === Tar::COMPRESS_GZIP) {
+ gzclose($this->fh);
+ } elseif($this->comptype === Tar::COMPRESS_BZIP) {
+ bzclose($this->fh);
+ } else {
+ fclose($this->fh);
+ }
+
+ $this->file = '';
+ $this->fh = 0;
+ }
+
+ $this->closed = true;
+ }
+
+ /**
+ * Returns the created in-memory archive data
+ *
+ * This implicitly calls close() on the Archive
+ */
+ public function getArchive($comptype = Tar::COMPRESS_AUTO, $complevel = 9) {
+ $this->close();
+
+ if($comptype === Tar::COMPRESS_AUTO) $comptype = $this->comptype;
+ $this->compressioncheck($comptype);
+
+ if($comptype === Tar::COMPRESS_GZIP) return gzcompress($this->memory, $complevel);
+ if($comptype === Tar::COMPRESS_BZIP) return bzcompress($this->memory);
+ return $this->memory;
+ }
+
+ /**
+ * Save the created in-memory archive data
+ *
+ * Note: It more memory effective to specify the filename in the create() function and
+ * let the library work on the new file directly.
+ *
+ * @param $file
+ * @param int $comptype
+ * @param int $complevel
+ * @throws TarIOException
+ */
+ public function save($file, $comptype = Tar::COMPRESS_AUTO, $complevel = 9) {
+ if($comptype === Tar::COMPRESS_AUTO) $comptype = $this->filetype($file);
+
+ if(!file_put_contents($file, $this->getArchive($comptype, $complevel))) {
+ throw new TarIOException('Could not write to file: '.$file);
+ }
+ }
+
+ /**
+ * Read from the open file pointer
+ *
+ * @param int $length bytes to read
+ * @return string
+ */
+ protected function readbytes($length) {
+ if($this->comptype === Tar::COMPRESS_GZIP) {
+ return @gzread($this->fh, $length);
+ } elseif($this->comptype === Tar::COMPRESS_BZIP) {
+ return @bzread($this->fh, $length);
+ } else {
+ return @fread($this->fh, $length);
+ }
+ }
+
+ /**
+ * Write to the open filepointer or memory
+ *
+ * @param string $data
+ * @throws TarIOException
+ * @return int number of bytes written
+ */
+ protected function writebytes($data) {
+ if(!$this->file) {
+ $this->memory .= $data;
+ $written = strlen($data);
+ } elseif($this->comptype === Tar::COMPRESS_GZIP) {
+ $written = @gzwrite($this->fh, $data);
+ } elseif($this->comptype === Tar::COMPRESS_BZIP) {
+ $written = @bzwrite($this->fh, $data);
+ } else {
+ $written = @fwrite($this->fh, $data);
+ }
+ if($written === false) throw new TarIOException('Failed to write to archive stream');
+ return $written;
+ }
+
+ /**
+ * Skip forward in the open file pointer
+ *
+ * This is basically a wrapper around seek() (and a workaround for bzip2)
+ *
+ * @param int $bytes seek to this position
+ */
+ function skipbytes($bytes) {
+ if($this->comptype === Tar::COMPRESS_GZIP) {
+ @gzseek($this->fh, $bytes, SEEK_CUR);
+ } elseif($this->comptype === Tar::COMPRESS_BZIP) {
+ // there is no seek in bzip2, we simply read on
+ @bzread($this->fh, $bytes);
+ } else {
+ @fseek($this->fh, $bytes, SEEK_CUR);
+ }
+ }
+
+ /**
+ * Write a file header
+ *
+ * @param string $name
+ * @param int $uid
+ * @param int $gid
+ * @param int $perm
+ * @param int $size
+ * @param int $mtime
+ * @param string $typeflag Set to '5' for directories
+ */
+ protected function writeFileHeader($name, $uid, $gid, $perm, $size, $mtime, $typeflag = '') {
+ // handle filename length restrictions
+ $prefix = '';
+ $namelen = strlen($name);
+ if($namelen > 100) {
+ $file = basename($name);
+ $dir = dirname($name);
+ if(strlen($file) > 100 || strlen($dir) > 155) {
+ // we're still too large, let's use GNU longlink
+ $this->writeFileHeader('././@LongLink', 0, 0, 0, $namelen, 0, 'L');
+ for($s = 0; $s < $namelen; $s += 512) {
+ $this->writebytes(pack("a512", substr($name, $s, 512)));
+ }
+ $name = substr($name, 0, 100); // cut off name
+ } else {
+ // we're fine when splitting, use POSIX ustar
+ $prefix = $dir;
+ $name = $file;
+ }
+ }
+
+ // values are needed in octal
+ $uid = sprintf("%6s ", decoct($uid));
+ $gid = sprintf("%6s ", decoct($gid));
+ $perm = sprintf("%6s ", decoct($perm));
+ $size = sprintf("%11s ", decoct($size));
+ $mtime = sprintf("%11s", decoct($mtime));
+
+ $data_first = pack("a100a8a8a8a12A12", $name, $perm, $uid, $gid, $size, $mtime);
+ $data_last = pack("a1a100a6a2a32a32a8a8a155a12", $typeflag, '', 'ustar', '', '', '', '', '', $prefix, "");
+
+ for($i = 0, $chks = 0; $i < 148; $i++)
+ $chks += ord($data_first[$i]);
+
+ for($i = 156, $chks += 256, $j = 0; $i < 512; $i++, $j++)
+ $chks += ord($data_last[$j]);
+
+ $this->writebytes($data_first);
+
+ $chks = pack("a8", sprintf("%6s ", decoct($chks)));
+ $this->writebytes($chks.$data_last);
+ }
+
+ /**
+ * Decode the given tar file header
+ *
+ * @param string $block a 512 byte block containign the header data
+ * @return array|bool
+ */
+ protected function parseHeader($block) {
+ if(!$block || strlen($block) != 512) return false;
+
+ for($i = 0, $chks = 0; $i < 148; $i++)
+ $chks += ord($block[$i]);
+
+ for($i = 156, $chks += 256; $i < 512; $i++)
+ $chks += ord($block[$i]);
+
+ $header = @unpack("a100filename/a8perm/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", $block);
+ if(!$header) return false;
+
+ $return['checksum'] = OctDec(trim($header['checksum']));
+ if($return['checksum'] != $chks) return false;
+
+ $return['filename'] = trim($header['filename']);
+ $return['perm'] = OctDec(trim($header['perm']));
+ $return['uid'] = OctDec(trim($header['uid']));
+ $return['gid'] = OctDec(trim($header['gid']));
+ $return['size'] = OctDec(trim($header['size']));
+ $return['mtime'] = OctDec(trim($header['mtime']));
+ $return['typeflag'] = $header['typeflag'];
+ $return['link'] = trim($header['link']);
+ $return['uname'] = trim($header['uname']);
+ $return['gname'] = trim($header['gname']);
+
+ // Handle ustar Posix compliant path prefixes
+ if(trim($header['prefix'])) $return['filename'] = trim($header['prefix']).'/'.$return['filename'];
+
+ // Handle Long-Link entries from GNU Tar
+ if($return['typeflag'] == 'L') {
+ // following data block(s) is the filename
+ $filename = trim($this->readbytes(ceil($header['size'] / 512) * 512));
+ // next block is the real header
+ $block = $this->readbytes(512);
+ $return = $this->parseHeader($block);
+ // overwrite the filename
+ $return['filename'] = $filename;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Cleans up a path and removes relative parts
+ *
+ * @param string $p_dir
+ * @return string
+ */
+ protected function cleanPath($p_dir) {
+ $r = '';
+ if($p_dir) {
+ $subf = explode("/", $p_dir);
+
+ for($i = count($subf) - 1; $i >= 0; $i--) {
+ if($subf[$i] == ".") {
+ # do nothing
+ } elseif($subf[$i] == "..") {
+ $i--;
+ } elseif(!$subf[$i] && $i != count($subf) - 1 && $i) {
+ # do nothing
+ } else {
+ $r = $subf[$i].($i != (count($subf) - 1) ? "/".$r : "");
+ }
+ }
+ }
+ return $r;
+ }
+
+ /**
+ * Checks if the given compression type is available and throws an exception if not
+ *
+ * @param $comptype
+ * @throws TarIllegalCompressionException
+ */
+ protected function compressioncheck($comptype) {
+ if($comptype === Tar::COMPRESS_GZIP && !function_exists('gzopen')) {
+ throw new TarIllegalCompressionException('No gzip support available');
+ }
+
+ if($comptype === Tar::COMPRESS_BZIP && !function_exists('bzopen')) {
+ throw new TarIllegalCompressionException('No bzip2 support available');
+ }
+ }
+
+ /**
+ * Guesses the wanted compression from the given filename extension
+ *
+ * You don't need to call this yourself. It's used when you pass Tar::COMPRESS_AUTO somewhere
+ *
+ * @param string $file
+ * @return int
+ */
+ public function filetype($file) {
+ $file = strtolower($file);
+ if(substr($file, -3) == '.gz' || substr($file, -4) == '.tgz') {
+ $comptype = Tar::COMPRESS_GZIP;
+ } elseif(substr($file, -4) == '.bz2' || substr($file, -4) == '.tbz') {
+ $comptype = Tar::COMPRESS_BZIP;
+ } else {
+ $comptype = Tar::COMPRESS_NONE;
+ }
+ return $comptype;
+ }
+}
+
+class TarIOException extends Exception {
+}
+
+class TarIllegalCompressionException extends Exception {
+}
diff --git a/inc/TarLib.class.php b/inc/TarLib.class.php
index e04c47cb8..ae08039ec 100644
--- a/inc/TarLib.class.php
+++ b/inc/TarLib.class.php
@@ -1,71 +1,14 @@
<?php
-/**
- * TAR format class - Creates TAR archives
- *
- * This class is part or the MaxgComp suite and originally named
- * MaxgTar class.
- *
- * Modified for Dokuwiki
- *
- * @license LGPL-2.1
- * @link http://docs.maxg.info
- * @author Bouchon <tarlib@bouchon.org> (Maxg)
- * @author Christopher Smith <chris@jalakai.co.uk>
- */
/**
- * Those constants represent the compression method to use.
- * COMPRESS_GZIP is used for the GZIP compression; COMPRESS_BZIP for
- * BZIP2 and COMPRESS_NONE for no compression.
- *
- * On the other hand, COMPRESS_AUTO is a bit harder. It will first check
- * if the zlib extensions are loaded.
- * If it is, GZIP will be used. Else it will check if the bz2 extensions
- * are loaded. If it is, BZIP2 will be used. Else no compression will be
- * performed.
- *
- * You can then use getCompression() to know the compression chosen.
- *
- * If you selected a compression which can't be used (i.e extension not
- * present), it will be just disabled, and won't produce any error !
- * As a consequence, getCompression() will return COMPRESS_NONE
- *
- * ARCHIVE_DYNAMIC can be passed as the first argument of the constructor, to
- * create an archive in memory instead of a file. See also: MaxgTar(),
- * getDynamicArchive() and writeArchive()
- *
- * ARCHIVE_RENAMECOMP is a flag that can be multiplied by the compression method
- * (i.e COMPRESS_AUTO * ARCHIVE_RENAMECOMP). This will add the correct extension
- * to the archive name, which is useful with COMPRESS_AUTO, ie .bz2 if you gave
- * COMPRESS_BZIP. See also getCompression(TRUE) which does exactly the
- * same
+ * This is a compatibility wrapper around the new Tar class
*
- * COMPRESS_DETECT does exactly the opposite and try to detect the
- * compression to use to read the archive depending on its extension. (i.e if
- * the archive ends with .tar.gz TarLib will try to decompress it with
- * GZIP). See also setCompression()
+ * Use of this library is strongly discouraged. Only basic extraction is wrapped,
+ * everything else will fail.
*
- * FULL_ARCHIVE is a -1 constant that means "the complete archive" when
- * extracting. This is explained in Extract()
+ * @deprecated 2012-11-06
*/
-#define('COMPRESS_GZIP',1);
-#define('COMPRESS_BZIP',2);
-#define('COMPRESS_AUTO',3);
-#define('COMPRESS_NONE',0);
-#define('TARLIB_VERSION','1.2');
-#define('FULL_ARCHIVE',-1);
-#define('ARCHIVE_DYNAMIC',0);
-#define('ARCHIVE_RENAMECOMP',5);
-#define('COMPRESS_DETECT',-1);
-
class TarLib {
- var $_comptype;
- var $_compzlevel;
- var $_fp;
- var $_memdat;
- var $_nomf;
- var $_result;
- var $_initerror;
const COMPRESS_GZIP = 1;
const COMPRESS_BZIP = 2;
@@ -77,845 +20,68 @@ class TarLib {
const ARCHIVE_RENAMECOMP = 5;
const COMPRESS_DETECT = -1;
- /**
- * constructor, initialize the class
- *
- * The constructor initialize the variables and prepare the class for the
- * archive, and return the object created. Note that you can use multiple
- * instances of the MaxgTar class, if you call this function another time and
- * store the object in an other variable.
- *
- * In fact, MaxgTar accepts the following arguments (all are optional) :
- *
- * filename can be either a file name (absolute or relative). In this
- * case, it can be used both for reading and writing. You can also open
- * remote archive if you add a protocole name at the beginning of the file
- * (ie https://host.dom/archive.tar.gz), but for reading only and if the
- * directive allow_url_fopen is enabled in PHP.INI (this can be checked with
- * TarInfo()). If you pass a file that doesn't exist, the script
- * will try to create it. If the archive already exists and contains files,
- * you can use Add() to append files.But by default this parameter
- * is ARCHIVE_DYNAMIC (write only) so the archive is created in memory and
- * can be sent to a file [writeArchive()] or to the client
- * [sendClient()]
- *
- * compression_type should be a constant that represents a type of
- * compression, or its integer value. The different values are described in
- * the constants.
- *
- * compression_level is an integer between 1 and 9 (by default) an
- * represent the GZIP or BZIP compression level. 1 produce fast compression,
- * and 9 produce smaller files. See the RFC 1952 for more infos.
- */
- function __construct($p_filen = TarLib::ARCHIVE_DYNAMIC, $p_comptype = TarLib::COMPRESS_AUTO, $p_complevel = 9) {
- $this->_initerror = 0;
- $this->_nomf = $p_filen;
- $flag = 0;
- if($p_comptype && $p_comptype % 5 == 0) {
- $p_comptype /= TarLib::ARCHIVE_RENAMECOMP;
- $flag = 1;
- }
+ private $file = '';
+ private $tar;
- if($p_complevel > 0 && $p_complevel <= 9) $this->_compzlevel = $p_complevel;
- else $this->_compzlevel = 9;
+ public $_result = true;
- if($p_comptype == TarLib::COMPRESS_DETECT) {
- if(strtolower(substr($p_filen, -3)) == '.gz') $p_comptype = TarLib::COMPRESS_GZIP;
- elseif(strtolower(substr($p_filen, -4)) == '.bz2') $p_comptype = TarLib::COMPRESS_BZIP;
- else $p_comptype = TarLib::COMPRESS_NONE;
- }
+ function __construct($file, $comptype = TarLib::COMPRESS_AUTO, $complevel = 9) {
+ if(!$file) $this->error('__construct', '$file');
- switch($p_comptype) {
+ $this->file = $file;
+ switch($comptype) {
+ case TarLib::COMPRESS_AUTO:
+ case TarLib::COMPRESS_DETECT:
+ $comptype = Tar::COMPRESS_AUTO;
+ break;
case TarLib::COMPRESS_GZIP:
- if(!extension_loaded('zlib')) $this->_initerror = -1;
- $this->_comptype = TarLib::COMPRESS_GZIP;
+ $comptype = Tar::COMPRESS_GZIP;
break;
-
case TarLib::COMPRESS_BZIP:
- if(!extension_loaded('bz2')) $this->_initerror = -2;
- $this->_comptype = TarLib::COMPRESS_BZIP;
+ $comptype = Tar::COMPRESS_BZIP;
break;
-
- case TarLib::COMPRESS_AUTO:
- if(extension_loaded('zlib'))
- $this->_comptype = TarLib::COMPRESS_GZIP;
- elseif(extension_loaded('bz2'))
- $this->_comptype = TarLib::COMPRESS_BZIP;
- else
- $this->_comptype = TarLib::COMPRESS_NONE;
- break;
-
default:
- $this->_comptype = TarLib::COMPRESS_NONE;
- }
-
- if($this->_initerror < 0) $this->_comptype = TarLib::COMPRESS_NONE;
-
- if($flag) $this->_nomf .= '.'.$this->getCompression(1);
- $this->_result = true;
- }
-
- /**
- * Recycle a TAR object.
- *
- * This function does exactly the same as TarLib (constructor), except it
- * returns a status code.
- */
- function setArchive($p_name = '', $p_comp = TarLib::COMPRESS_AUTO, $p_level = 9) {
- $this->_CompTar();
- $this->__construct($p_name, $p_comp, $p_level);
- return $this->_result;
- }
-
- /**
- * Get the compression used to generate the archive
- *
- * This is a very useful function when you're using dynamical archives.
- * Besides, if you let the script chose which compression to use, you'll have
- * a problem when you'll want to send it to the client if you don't know
- * which compression was used.
- *
- * There are two ways to call this function : if you call it without argument
- * or with FALSE, it will return the compression constants, explained on the
- * MaxgTar Constants. If you call it with GetExtension on TRUE it will
- * return the extension without starting dot (ie "tar" or "tar.bz2" or
- * "tar.gz")
- *
- * NOTE: This can be done with the flag ARCHIVE_RENAMECOMP, see the
- * MaxgTar Constants
- */
- function getCompression($ext = false) {
- $exts = Array('tar', 'tar.gz', 'tar.bz2');
- if($ext) return $exts[$this->_comptype];
- return $this->_comptype;
- }
-
- /**
- * Change the compression mode.
- *
- * This function will change the compression methode to read or write
- * the archive. See the MaxgTar Constants to see which constants you can use.
- * It may look strange, but it returns the GZIP compression level.
- */
- function setCompression($p_comp = TarLib::COMPRESS_AUTO) {
- $this->setArchive($this->_nomf, $p_comp, $this->_compzlevel);
- return $this->_compzlevel;
- }
-
- /**
- * Returns the compressed dynamic archive.
- *
- * When you're working with dynamic archives, use this function to grab
- * the final compressed archive in a string ready to be put in a SQL table or
- * in a file.
- */
- function getDynamicArchive() {
- return $this->_encode($this->_memdat);
- }
-
- /**
- * Write a dynamical archive into a file
- *
- * This function attempts to write a dynamicaly-genrated archive into
- * TargetFile on the webserver. It returns a TarErrorStr() status
- * code.
- *
- * To know the extension to add to the file if you're using AUTO_DETECT
- * compression, you can use getCompression().
- */
- function writeArchive($p_archive) {
- if(!$this->_memdat) return -7;
- $fp = @fopen($p_archive, 'wb');
- if(!$fp) return -6;
-
- fwrite($fp, $this->_memdat);
- fclose($fp);
-
- return true;
- }
-
- /**
- * Send a TAR archive to the client browser.
- *
- * This function will send an archive to the client, and return a status
- * code, but can behave differently depending on the arguments you give. All
- * arguments are optional.
- *
- * ClientName is used to specify the archive name to give to the browser. If
- * you don't give one, it will send the constructor filename or return an
- * error code in case of dynamical archive.
- *
- * FileName is optional and used to send a specific archive. Leave it blank
- * to send dynamical archives or the current working archive.
- *
- * If SendHeaders is enabled (by default), the library will send the HTTP
- * headers itself before it sends the contents. This headers are :
- * Content-Type, Content-Disposition, Content-Length and Accept-Range.
- *
- * Please note that this function DOES NOT stops the script so don't forget
- * to exit() to avoid your script sending other data and corrupt the archive.
- * Another note : for AUTO_DETECT dynamical archives you can know the
- * extension to add to the name with getCompression()
- */
- function sendClient($name = '', $archive = '', $headers = true) {
- if(!$name && !$this->_nomf) return -9;
- if(!$archive && !$this->_memdat) return -10;
- if(!$name) $name = utf8_basename($this->_nomf);
-
- if($archive) {
- if(!file_exists($archive)) return -11;
- }
- $decoded = $this->getDynamicArchive();
-
- if($headers) {
- header('Content-Type: application/x-gtar');
- header('Content-Disposition: attachment; filename='.utf8_basename($name));
- header('Accept-Ranges: bytes');
- header('Content-Length: '.($archive ? filesize($archive) : strlen($decoded)));
+ $comptype = Tar::COMPRESS_NONE;
}
- if($archive) {
- $fp = @fopen($archive, 'rb');
- if(!$fp) return -4;
+ $this->complevel = $complevel;
- while(!feof($fp)) echo fread($fp, 2048);
- } else {
- echo $decoded;
+ try {
+ $this->tar = new Tar();
+ $this->tar->open($file, $comptype);
+ } catch(Exception $e) {
+ $this->_result = false;
}
-
- return true;
}
- /**
- * Extract part or totality of the archive.
- *
- * This function can extract files from an archive, and returns then a
- * status codes that can be converted with TarErrorStr() into a
- * human readable message.
- *
- * Only the first argument is required, What and it can be either the
- * constant FULL_ARCHIVE or an indexed array containing each file you want to
- * extract.
- *
- * To contains the target folder to extract the archive. It is optional and
- * the default value is '.' which means the current folder. If the target
- * folder doesn't exist, the script attempts to create it and give it
- * permissions 0777 by default.
- *
- * RemovePath is very usefull when you want to extract files from a subfoler
- * in the archive to a root folder. For instance, if you have a file in the
- * archive called some/sub/folder/test.txt and you want to extract it to the
- * script folder, you can call Extract with To = '.' and RemovePath =
- * 'some/sub/folder/'
- *
- * FileMode is optional and its default value is 0755. It is in fact the UNIX
- * permission in octal mode (prefixed with a 0) that will be given on each
- * extracted file.
- */
function Extract($p_what = TarLib::FULL_ARCHIVE, $p_to = '.', $p_remdir = '', $p_mode = 0755) {
- if(!$this->_OpenRead()) return -4;
- // if(!@is_dir($p_to)) if(!@mkdir($p_to, 0777)) return -8; --CS
- if(!@is_dir($p_to)) if(!$this->_dirApp($p_to)) return -8; //--CS (route through correct dir fn)
-
- $ok = $this->_extractList($p_to, $p_what, $p_remdir, $p_mode);
- $this->_CompTar();
-
- return $ok;
- }
-
- /**
- * Create a new package with the given files
- *
- * This function will attempt to create a new archive with global headers
- * then add the given files into. If the archive is a real file, the
- * contents are written directly into the file. If it is a dynamic archive,
- * contents are only stored in memory. This function should not be used to
- * add files to an existing archive, you should use Add() instead.
- *
- * The FileList actually supports three different modes:
- *
- * - You can pass a string containing filenames separated by pipes '|'.
- * In this case thes file are read from the filesystem and the root folder
- * is the folder running script located. NOT RECOMMENDED
- *
- * - You can also give an indexed array containing the filenames. The
- * behaviour for the content reading is the same as above.
- *
- * - You can pass an array of arrays. For each file use an array where the
- * first element contains the filename and the second contains the file
- * contents. You can even add empty folders to the package if the filename
- * has a leading '/'. Once again, have a look at the exemples to understand
- * better.
- *
- * Note you can also give arrays with both dynamic contents and static files.
- *
- * The optional parameter RemovePath can be used to delete a part of the tree
- * of the filename you're adding, for instance if you're adding in the root
- * of a package a file that is stored somewhere in the server tree.
- *
- * On the contrary the parameter AddPath can be used to add a prefix folder
- * to the file you store. Note also that the RemovePath is applied before the
- * AddPath is added, so it HAS a sense to use both parameters together.
- */
- function Create($p_filelist, $p_add = '', $p_rem = '') {
- if(!$fl = $this->_fetchFilelist($p_filelist)) return -5;
- if(!$this->_OpenWrite()) return -6;
-
- $ok = $this->_addFileList($fl, $p_add, $p_rem);
-
- if($ok) {
- $this->_writeFooter();
- } else {
- $this->_CompTar();
- @unlink($this->_nomf);
+ if($p_what != TarLib::FULL_ARCHIVE) {
+ $this->error('Extract', 'Ep_what');
+ return 0;
}
- return $ok;
- }
-
- /**
- * Add files to an existing package.
- *
- * This function does exactly the same as Create() exept it
- * will append the given files at the end of the archive.
- *
- * Note: This is only supported for dynamic in memory files and uncompressed
- * tar files
- *
- * This function returns a status code, you can use TarErrorStr() on
- * it to get the human-readable description of the error.
- */
- function Add($p_filelist, $p_add = '', $p_rem = '') {
- if($this->_nomf !== TarLib::ARCHIVE_DYNAMIC &&
- $this->_comptype !== TarLib::COMPRESS_NONE
- ) {
- return -12;
+ try {
+ $this->tar->extract($p_to, $p_remdir);
+ } catch(Exception $e) {
+ return 0;
}
-
- if(($this->_nomf !== TarLib::ARCHIVE_DYNAMIC && !$this->_fp) ||
- ($this->_nomf === TarLib::ARCHIVE_DYNAMIC && !$this->_memdat)
- ) {
- return $this->Create($p_filelist, $p_add, $p_rem);
- }
-
- if(!$fl = $this->_fetchFilelist($p_filelist)) return -5;
- return $this->_append($fl, $p_add, $p_rem);
+ return 1;
}
- /**
- * Read the contents of a TAR archive
- *
- * This function attempts to get the list of the files stored in the
- * archive, and return either an error code or an indexed array of
- * associative array containing for each file the following information :
- *
- * checksum Tar Checksum of the file
- * filename The full name of the stored file (up to 100 c.)
- * mode UNIX permissions in DECIMAL, not octal
- * uid The Owner ID
- * gid The Group ID
- * size Uncompressed filesize
- * mtime Timestamp of last modification
- * typeflag Empty for files, set for folders
- * link For the links, did you guess it ?
- * uname Owner name
- * gname Group name
- */
- function ListContents() {
- if(!$this->_nomf) return -3;
- if(!$this->_OpenRead()) return -4;
+ function error($func, $param = '') {
+ $error = 'TarLib is deprecated and should no longer be used.';
- $result = Array();
-
- while($dat = $this->_read(512)) {
- $dat = $this->_readHeader($dat);
- if(!is_array($dat)) continue;
-
- $this->_seek(ceil($dat['size'] / 512) * 512, 1);
- $result[] = $dat;
- }
-
- return $result;
- }
-
- /**
- * Convert a status code into a human readable message
- *
- * Some MaxgTar functions like Create(), Add() ... return numerical
- * status code. You can pass them to this function to grab their english
- * equivalent.
- */
- function TarErrorStr($i) {
- $ecodes = Array(
- 1 => true,
- 0 => "Undocumented error",
- -1 => "Can't use COMPRESS_GZIP compression : ZLIB extensions are not loaded !",
- -2 => "Can't use COMPRESS_BZIP compression : BZ2 extensions are not loaded !",
- -3 => "You must set a archive file to read the contents !",
- -4 => "Can't open the archive file for read !",
- -5 => "Invalide file list !",
- -6 => "Can't open the archive in write mode !",
- -7 => "There is no ARCHIVE_DYNAMIC to write !",
- -8 => "Can't create the directory to extract files !",
- -9 => "Please pass a archive name to send if you made created an ARCHIVE_DYNAMIC !",
- -10 => "You didn't pass an archive filename and there is no stored ARCHIVE_DYNAMIC !",
- -11 => "Given archive doesn't exist !",
- -12 => "Appending not supported for compressed files"
- );
-
- return isset($ecodes[$i]) ? $ecodes[$i] : $ecodes[0];
- }
-
- /**
- * Seek in the data stream
- *
- * @todo probably broken for bzip tars
- * @param int $p_flen seek to this position
- * @param bool $tell seek from current position?
- */
- function _seek($p_flen, $tell = false) {
- if($this->_nomf === TarLib::ARCHIVE_DYNAMIC)
- $this->_memdat = substr($this->_memdat, 0, ($tell ? strlen($this->_memdat) : 0) + $p_flen);
- elseif($this->_comptype == TarLib::COMPRESS_GZIP)
- @gzseek($this->_fp, ($tell ? @gztell($this->_fp) : 0) + $p_flen);
- elseif($this->_comptype == TarLib::COMPRESS_BZIP)
- @fseek($this->_fp, ($tell ? @ftell($this->_fp) : 0) + $p_flen);
- else
- @fseek($this->_fp, ($tell ? @ftell($this->_fp) : 0) + $p_flen);
- }
-
- /**
- * Open the archive for reading
- *
- * @return bool true if succesfull
- */
- function _OpenRead() {
- if($this->_comptype == TarLib::COMPRESS_GZIP)
- $this->_fp = @gzopen($this->_nomf, 'rb');
- elseif($this->_comptype == TarLib::COMPRESS_BZIP)
- $this->_fp = @bzopen($this->_nomf, 'rb');
- else
- $this->_fp = @fopen($this->_nomf, 'rb');
-
- return ($this->_fp ? true : false);
- }
-
- /**
- * Open the archive for writing
- *
- * @param string $add filemode
- * @return bool true on success
- */
- function _OpenWrite($add = 'w') {
- if($this->_nomf === TarLib::ARCHIVE_DYNAMIC) return true;
-
- if($this->_comptype == TarLib::COMPRESS_GZIP)
- $this->_fp = @gzopen($this->_nomf, $add.'b'.$this->_compzlevel);
- elseif($this->_comptype == TarLib::COMPRESS_BZIP)
- $this->_fp = @bzopen($this->_nomf, $add.'b');
- else
- $this->_fp = @fopen($this->_nomf, $add.'b');
-
- return ($this->_fp ? true : false);
- }
-
- /**
- * Closes the open file pointer
- */
- function _CompTar() {
- if($this->_nomf === TarLib::ARCHIVE_DYNAMIC || !$this->_fp) return;
-
- if($this->_comptype == TarLib::COMPRESS_GZIP) @gzclose($this->_fp);
- elseif($this->_comptype == TarLib::COMPRESS_BZIP) @bzclose($this->_fp);
- else @fclose($this->_fp);
- }
-
- /**
- * Read from the open file pointer
- *
- * @param int $p_len bytes to read
- * @return string
- */
- function _read($p_len) {
- if($this->_comptype == TarLib::COMPRESS_GZIP)
- return @gzread($this->_fp, $p_len);
- elseif($this->_comptype == TarLib::COMPRESS_BZIP)
- return @bzread($this->_fp, $p_len);
- else
- return @fread($this->_fp, $p_len);
- }
-
- /**
- * Write to the open filepointer or memory
- *
- * @param string $p_data
- * @return int
- */
- function _write($p_data) {
- if($this->_nomf === TarLib::ARCHIVE_DYNAMIC) {
- $this->_memdat .= $p_data;
- return strlen($p_data);
- } elseif($this->_comptype == TarLib::COMPRESS_GZIP) {
- return @gzwrite($this->_fp, $p_data);
- } elseif($this->_comptype == TarLib::COMPRESS_BZIP) {
- return @bzwrite($this->_fp, $p_data);
+ if($param) {
+ $error .= "In this compatibility wrapper, the function '$func' does not accept your value for".
+ "the parameter '$param' anymore.";
} else {
- return @fwrite($this->_fp, $p_data);
+ $error .= "The function '$func' no longer exists in this compatibility wrapper.";
}
- }
- /**
- * Compress given data according to the set compression method
- *
- * @param $p_dat
- * @return string
- */
- function _encode($p_dat) {
- if($this->_comptype == TarLib::COMPRESS_GZIP)
- return gzencode($p_dat, $this->_compzlevel);
- elseif($this->_comptype == TarLib::COMPRESS_BZIP)
- return bzcompress($p_dat, $this->_compzlevel);
- else return $p_dat;
+ msg($error, -1);
}
- /**
- * Decode the given tar file header
- *
- * @param $p_dat
- * @return array|bool
- */
- function _readHeader($p_dat) {
- if(!$p_dat || strlen($p_dat) != 512) return false;
-
- for($i = 0, $chks = 0; $i < 148; $i++)
- $chks += ord($p_dat[$i]);
-
- for($i = 156, $chks += 256; $i < 512; $i++)
- $chks += ord($p_dat[$i]);
-
- $headers = @unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $p_dat);
- if(!$headers) return false;
-
- $return['checksum'] = OctDec(trim($headers['checksum']));
- if($return['checksum'] != $chks) return false;
-
- $return['filename'] = trim($headers['filename']);
- $return['mode'] = OctDec(trim($headers['mode']));
- $return['uid'] = OctDec(trim($headers['uid']));
- $return['gid'] = OctDec(trim($headers['gid']));
- $return['size'] = OctDec(trim($headers['size']));
- $return['mtime'] = OctDec(trim($headers['mtime']));
- $return['typeflag'] = $headers['typeflag'];
- $return['link'] = trim($headers['link']);
- $return['uname'] = trim($headers['uname']);
- $return['gname'] = trim($headers['gname']);
-
- return $return;
- }
-
- /**
- * Builds a normalized file list
- *
- * @todo remove string support, use saner format
- *
- * @param $p_filelist
- * @return array|bool
- */
- function _fetchFilelist($p_filelist) {
- if(!$p_filelist || (is_array($p_filelist) && !@count($p_filelist))) return false;
-
- if(is_string($p_filelist)) {
- $p_filelist = explode('|', $p_filelist);
- if(!is_array($p_filelist)) $p_filelist = Array($p_filelist);
- }
-
- return $p_filelist;
- }
-
- /**
- * Adds files given as file list
- *
- * @param array $p_fl
- * @param string $p_addir
- * @param string $p_remdir
- * @return bool
- */
- function _addFileList($p_fl, $p_addir, $p_remdir) {
- foreach($p_fl as $file) {
- if(($file == $this->_nomf && $this->_nomf !== TarLib::ARCHIVE_DYNAMIC) || !$file || (!is_array($file) && !file_exists($file)))
- continue;
-
- if(!$this->_addFile($file, $p_addir, $p_remdir))
- continue;
-
- if(@is_dir($file)) {
- $d = @opendir($file);
-
- if(!$d) continue;
- readdir($d);
- readdir($d);
-
- while($f = readdir($d)) {
- if($file != ".") $tmplist[0] = "$file/$f";
- else $tmplist[0] = $d;
-
- $this->_addFileList($tmplist, $p_addir, $p_remdir);
- }
-
- closedir($d);
- unset($tmplist, $f);
- }
- }
- return true;
+ function __call($name, $arguments) {
+ $this->error($name);
}
-
- /**
- * Adds a single file
- *
- * @param array|string $p_fn
- * @param string $p_addir
- * @param string $p_remdir
- * @return bool
- */
- function _addFile($p_fn, $p_addir = '', $p_remdir = '') {
- $data = false;
- if(is_array($p_fn)) list($p_fn, $data) = $p_fn;
- $sname = $p_fn;
-
- if($p_remdir) {
- if(substr($p_remdir, -1) != '/') $p_remdir .= "/";
-
- if(substr($sname, 0, strlen($p_remdir)) == $p_remdir)
- $sname = substr($sname, strlen($p_remdir));
- }
-
- if($p_addir) $sname = $p_addir.(substr($p_addir, -1) == '/' ? '' : "/").$sname;
-
- // FIXME ustar should support up 256 chars
- if(strlen($sname) > 99) return false;
-
- if(@is_dir($p_fn)) {
- if(!$this->_writeFileHeader($p_fn, $sname)) return false;
- } else {
- if(!$data) {
- $fp = fopen($p_fn, 'rb');
- if(!$fp) return false;
- }
-
- if(!$this->_writeFileHeader($p_fn, $sname, ($data ? strlen($data) : false))) return false;
-
- if(!$data) {
- while(!feof($fp)) {
- $packed = pack("a512", fread($fp, 512));
- $this->_write($packed);
- }
- fclose($fp);
- } else {
- $len = strlen($data);
- for($s = 0; $s < $len; $s += 512) {
- $this->_write(pack("a512", substr($data, $s, 512)));
- }
- }
- }
-
- return true;
- }
-
- /**
- * Write the header for a file in the TAR archive
- *
- * @param string $p_file
- * @param string $p_sname
- * @param bool $p_data
- * @return bool
- */
- function _writeFileHeader($p_file, $p_sname, $p_data = false) {
- if(!$p_data) {
- if(!$p_sname) $p_sname = $p_file;
- $p_sname = $this->_pathTrans($p_sname);
-
- $h_info = stat($p_file);
- $h[0] = sprintf("%6s ", DecOct($h_info[4]));
- $h[] = sprintf("%6s ", DecOct($h_info[5]));
- $h[] = sprintf("%6s ", DecOct(fileperms($p_file)));
- clearstatcache();
- $h[] = sprintf("%11s ", DecOct(filesize($p_file)));
- $h[] = sprintf("%11s", DecOct(filemtime($p_file)));
-
- $dir = @is_dir($p_file) ? '5' : '';
- } else {
- $dir = '';
- $p_data = sprintf("%11s ", DecOct($p_data));
- $time = sprintf("%11s ", DecOct(time()));
- $h = Array(" 0 ", " 0 ", " 40777 ", $p_data, $time);
- }
-
- $data_first = pack("a100a8a8a8a12A12", $p_sname, $h[2], $h[0], $h[1], $h[3], $h[4]);
- $data_last = pack("a1a100a6a2a32a32a8a8a155a12", $dir, '', '', '', '', '', '', '', '', "");
-
- for($i = 0, $chks = 0; $i < 148; $i++)
- $chks += ord($data_first[$i]);
-
- for($i = 156, $chks += 256, $j = 0; $i < 512; $i++, $j++)
- $chks += ord($data_last[$j]);
-
- $this->_write($data_first);
-
- $chks = pack("a8", sprintf("%6s ", DecOct($chks)));
- $this->_write($chks.$data_last);
-
- return true;
- }
-
- /**
- * Append the given files to the already open archive
- *
- * @param array $p_filelist
- * @param string $p_addir
- * @param string $p_remdir
- * @return bool|int
- */
- function _append($p_filelist, $p_addir = "", $p_remdir = "") {
- if(!$this->_fp) if(!$this->_OpenWrite('a')) return -6;
-
- if($this->_nomf === TarLib::ARCHIVE_DYNAMIC) {
- $this->_memdat = substr($this->_memdat, 0, -512 * 2); // remove footer
- } else {
- clearstatcache();
- $s = filesize($this->_nomf);
-
- $this->_seek($s - (512 * 2)); // remove footer
- }
-
- $ok = $this->_addFileList($p_filelist, $p_addir, $p_remdir);
- $this->_writeFooter();
-
- return $ok;
- }
-
- /**
- * Cleans up a path and removes relative parts
- *
- * @param string $p_dir
- * @return string
- */
- function _pathTrans($p_dir) {
- $r = '';
- if($p_dir) {
- $subf = explode("/", $p_dir);
-
- for($i = count($subf) - 1; $i >= 0; $i--) {
- if($subf[$i] == ".") {
- # do nothing
- } elseif($subf[$i] == "..") {
- $i--;
- } elseif(!$subf[$i] && $i != count($subf) - 1 && $i) {
- # do nothing
- } else {
- $r = $subf[$i].($i != (count($subf) - 1) ? "/".$r : "");
- }
- }
- }
- return $r;
- }
-
- /**
- * Add the closing footer to the archive
- *
- * Physically, an archive consists of a series of file entries terminated by an end-of-archive entry, which
- * consists of two 512 blocks of zero bytes
- *
- * @link http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134
- */
- function _writeFooter() {
- $this->_write(pack("a512", ""));
- $this->_write(pack("a512", ""));
- }
-
- /**
- * @param $p_to
- * @param $p_files
- * @param $p_remdir
- * @param int $p_mode
- * @return array|bool|int|string
- */
- function _extractList($p_to, $p_files, $p_remdir, $p_mode = 0755) {
- if(!$p_to || ($p_to[0] != "/" && substr($p_to, 0, 3) != "../" && substr($p_to, 1, 3) != ":\\" && substr($p_to, 1, 2) != ":/")) /*" // <- PHP Coder bug */
- $p_to = "./$p_to";
-
- if($p_remdir && substr($p_remdir, -1) != '/') $p_remdir .= '/';
- $p_remdirs = strlen($p_remdir);
- while($dat = $this->_read(512)) {
- $headers = $this->_readHeader($dat);
- if(!$headers['filename']) continue;
-
- if($p_files == -1 || $p_files[0] == -1) {
- $extract = true;
- } else {
- $extract = false;
-
- foreach($p_files as $f) {
- if(substr($f, -1) == "/") {
- if((strlen($headers['filename']) > strlen($f)) && (substr($headers['filename'], 0, strlen($f)) == $f)) {
- $extract = true;
- break;
- }
- } elseif($f == $headers['filename']) {
- $extract = true;
- break;
- }
- }
- }
-
- if($extract) {
- $det[] = $headers;
- if($p_remdir && substr($headers['filename'], 0, $p_remdirs) == $p_remdir)
- $headers['filename'] = substr($headers['filename'], $p_remdirs);
-
- if($headers['filename'].'/' == $p_remdir && $headers['typeflag'] == '5') continue;
-
- if($p_to != "./" && $p_to != "/") {
- while($p_to{-1} == "/") $p_to = substr($p_to, 0, -1);
-
- if($headers['filename']{0} == "/")
- $headers['filename'] = $p_to.$headers['filename'];
- else
- $headers['filename'] = $p_to."/".$headers['filename'];
- }
-
- $ok = $this->_dirApp($headers['typeflag'] == "5" ? $headers['filename'] : dirname($headers['filename']));
- if($ok < 0) return $ok;
-
- if(!$headers['typeflag']) {
- if(!$fp = @fopen($headers['filename'], "wb")) return -6;
- $n = floor($headers['size'] / 512);
-
- for($i = 0; $i < $n; $i++) {
- fwrite($fp, $this->_read(512), 512);
- }
- if(($headers['size'] % 512) != 0) fwrite($fp, $this->_read(512), $headers['size'] % 512);
-
- fclose($fp);
- touch($headers['filename'], $headers['mtime']);
- chmod($headers['filename'], $p_mode);
- } else {
- $this->_seek(ceil($headers['size'] / 512) * 512, 1);
- }
- } else $this->_seek(ceil($headers['size'] / 512) * 512, 1);
- }
- return $det;
- }
-
- /**
- * Create a directory hierarchy in filesystem
- *
- * @param string $d
- * @return bool
- */
- function _dirApp($d) {
- // map to dokuwiki function (its more robust)
- return io_mkdir_p($d);
- }
-
-}
-
+} \ No newline at end of file
diff --git a/inc/actions.php b/inc/actions.php
index f65b47451..4083b0454 100644
--- a/inc/actions.php
+++ b/inc/actions.php
@@ -711,21 +711,28 @@ function act_subscription($act){
$target = $params['target'];
$style = $params['style'];
- $data = $params['data'];
$action = $params['action'];
// Perform action.
- if (!subscription_set($_SERVER['REMOTE_USER'], $target, $style, $data)) {
+ $sub = new Subscription();
+ if($action == 'unsubscribe'){
+ $ok = $sub->remove($target, $_SERVER['REMOTE_USER'], $style);
+ }else{
+ $ok = $sub->add($target, $_SERVER['REMOTE_USER'], $style);
+ }
+
+ if($ok) {
+ msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
+ prettyprint_id($target)), 1);
+ act_redirect($ID, $act);
+ } else {
throw new Exception(sprintf($lang["subscr_{$action}_error"],
hsc($INFO['userinfo']['name']),
prettyprint_id($target)));
}
- msg(sprintf($lang["subscr_{$action}_success"], hsc($INFO['userinfo']['name']),
- prettyprint_id($target)), 1);
- act_redirect($ID, $act);
// Assure that we have valid data if act_redirect somehow fails.
- $INFO['subscribed'] = get_info_subscribed();
+ $INFO['subscribed'] = $sub->user_subscription();
return 'show';
}
@@ -777,8 +784,7 @@ function subscription_handle_post(&$params) {
$style = null;
}
- $data = in_array($style, array('list', 'digest')) ? time() : null;
- $params = compact('target', 'style', 'data', 'action');
+ $params = compact('target', 'style', 'action');
}
//Setup VIM: ex: et ts=2 :
diff --git a/inc/auth.php b/inc/auth.php
index 76356c37f..7f427bd8d 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -536,9 +536,10 @@ function auth_aclcheck($id, $user, $groups) {
return AUTH_ADMIN;
}
- $ci = '';
- if(!$auth->isCaseSensitive()) $ci = 'ui';
-
+ if(!$auth->isCaseSensitive()) {
+ $user = utf8_strtolower($user);
+ $groups = array_map('utf8_strtolower', $groups);
+ }
$user = $auth->cleanUser($user);
$groups = array_map(array($auth, 'cleanGroup'), (array) $groups);
$user = auth_nameencode($user);
@@ -562,11 +563,14 @@ function auth_aclcheck($id, $user, $groups) {
}
//check exact match first
- $matches = preg_grep('/^'.preg_quote($id, '/').'\s+(\S+)\s+/'.$ci, $AUTH_ACL);
+ $matches = preg_grep('/^'.preg_quote($id, '/').'\s+(\S+)\s+/u', $AUTH_ACL);
if(count($matches)) {
foreach($matches as $match) {
$match = preg_replace('/#.*$/', '', $match); //ignore comments
$acl = preg_split('/\s+/', $match);
+ if(!$auth->isCaseSensitive() && $acl[1] !== '@ALL') {
+ $acl[1] = utf8_strtolower($acl[1]);
+ }
if(!in_array($acl[1], $groups)) {
continue;
}
@@ -577,7 +581,7 @@ function auth_aclcheck($id, $user, $groups) {
}
if($perm > -1) {
//we had a match - return it
- return $perm;
+ return (int) $perm;
}
}
@@ -589,11 +593,14 @@ function auth_aclcheck($id, $user, $groups) {
}
do {
- $matches = preg_grep('/^'.preg_quote($path, '/').'\s+(\S+)\s+/'.$ci, $AUTH_ACL);
+ $matches = preg_grep('/^'.preg_quote($path, '/').'\s+(\S+)\s+/u', $AUTH_ACL);
if(count($matches)) {
foreach($matches as $match) {
$match = preg_replace('/#.*$/', '', $match); //ignore comments
$acl = preg_split('/\s+/', $match);
+ if(!$auth->isCaseSensitive() && $acl[1] !== '@ALL') {
+ $acl[1] = utf8_strtolower($acl[1]);
+ }
if(!in_array($acl[1], $groups)) {
continue;
}
@@ -604,7 +611,7 @@ function auth_aclcheck($id, $user, $groups) {
}
//we had a match - return it
if($perm != -1) {
- return $perm;
+ return (int) $perm;
}
}
//get next higher namespace
@@ -774,23 +781,19 @@ function register() {
return false;
}
- // create substitutions for use in notification email
- $substitutions = array(
- 'NEWUSER' => $login,
- 'NEWNAME' => $fullname,
- 'NEWEMAIL' => $email,
- );
+ // send notification about the new user
+ $subscription = new Subscription();
+ $subscription->send_register($login, $fullname, $email);
+ // are we done?
if(!$conf['autopasswd']) {
msg($lang['regsuccess2'], 1);
- notify('', 'register', '', $login, false, $substitutions);
return true;
}
- // autogenerated password? then send him the password
+ // autogenerated password? then send password to user
if(auth_sendPassword($login, $pass)) {
msg($lang['regsuccess'], 1);
- notify('', 'register', '', $login, false, $substitutions);
return true;
} else {
msg($lang['regmailfail'], -1);
diff --git a/inc/changelog.php b/inc/changelog.php
index 688aebfd6..9768fea51 100644
--- a/inc/changelog.php
+++ b/inc/changelog.php
@@ -258,6 +258,7 @@ function getRecentsSince($from,$to=null,$ns='',$flags=0){
} else {
$lines = @file($conf['changelog']);
}
+ if(!$lines) return $recent;
// we start searching at the end of the list
$lines = array_reverse($lines);
diff --git a/inc/common.php b/inc/common.php
index 20baed6c0..db39affc6 100644
--- a/inc/common.php
+++ b/inc/common.php
@@ -107,9 +107,11 @@ function pageinfo() {
$info['isadmin'] = false;
$info['ismanager'] = false;
if(isset($_SERVER['REMOTE_USER'])) {
+ $sub = new Subscription();
+
$info['userinfo'] = $USERINFO;
$info['perm'] = auth_quickaclcheck($ID);
- $info['subscribed'] = get_info_subscribed();
+ $info['subscribed'] = $sub->user_subscription();
$info['client'] = $_SERVER['REMOTE_USER'];
if($info['perm'] == AUTH_ADMIN) {
@@ -309,7 +311,11 @@ function breadcrumbs() {
*
* This is run on a ID before it is outputted somewhere
* currently used to replace the colon with something else
- * on Windows systems and to have proper URL encoding
+ * on Windows (non-IIS) systems and to have proper URL encoding
+ *
+ * See discussions at https://github.com/splitbrain/dokuwiki/pull/84 and
+ * https://github.com/splitbrain/dokuwiki/pull/173 why we use a whitelist of
+ * unaffected servers instead of blacklisting affected servers here.
*
* Urlencoding is ommitted when the second parameter is false
*
@@ -320,7 +326,8 @@ function idfilter($id, $ue = true) {
if($conf['useslash'] && $conf['userewrite']) {
$id = strtr($id, ':', '/');
} elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' &&
- $conf['userewrite']
+ $conf['userewrite'] &&
+ strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') === false
) {
$id = strtr($id, ':', ';');
}
@@ -1103,90 +1110,31 @@ function saveOldRevision($id) {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function notify($id, $who, $rev = '', $summary = '', $minor = false, $replace = array()) {
- global $lang;
global $conf;
- global $INFO;
- global $DIFF_INLINESTYLES;
// decide if there is something to do, eg. whom to mail
if($who == 'admin') {
if(empty($conf['notify'])) return false; //notify enabled?
- $text = rawLocale('mailtext');
- $to = $conf['notify'];
- $bcc = '';
+ $tpl = 'mailtext';
+ $to = $conf['notify'];
} elseif($who == 'subscribers') {
- if(!$conf['subscribers']) return false; //subscribers enabled?
+ if(!actionOK('subscribe')) return false; //subscribers enabled?
if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return false; //skip minors
$data = array('id' => $id, 'addresslist' => '', 'self' => false);
trigger_event(
'COMMON_NOTIFY_ADDRESSLIST', $data,
- 'subscription_addresslist'
+ array(new Subscription(), 'notifyaddresses')
);
- $bcc = $data['addresslist'];
- if(empty($bcc)) return false;
- $to = '';
- $text = rawLocale('subscr_single');
- } elseif($who == 'register') {
- if(empty($conf['registernotify'])) return false;
- $text = rawLocale('registermail');
- $to = $conf['registernotify'];
- $bcc = '';
+ $to = $data['addresslist'];
+ if(empty($to)) return false;
+ $tpl = 'subscr_single';
} else {
return false; //just to be safe
}
- // prepare replacements (keys not set in hrep will be taken from trep)
- $trep = array(
- 'NEWPAGE' => wl($id, '', true, '&'),
- 'PAGE' => $id,
- 'SUMMARY' => $summary
- );
- $trep = array_merge($trep, $replace);
- $hrep = array();
-
// prepare content
- if($who == 'register') {
- $subject = $lang['mail_new_user'].' '.$summary;
- } elseif($rev) {
- $subject = $lang['mail_changed'].' '.$id;
- $trep['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
- $old_content = rawWiki($id, $rev);
- $new_content = rawWiki($id);
- $df = new Diff(explode("\n", $old_content),
- explode("\n", $new_content));
- $dformat = new UnifiedDiffFormatter();
- $tdiff = $dformat->format($df);
-
- $DIFF_INLINESTYLES = true;
- $hdf = new Diff(explode("\n", hsc($old_content)),
- explode("\n", hsc($new_content)));
- $dformat = new InlineDiffFormatter();
- $hdiff = $dformat->format($hdf);
- $hdiff = '<table>'.$hdiff.'</table>';
- $DIFF_INLINESTYLES = false;
- } else {
- $subject = $lang['mail_newpage'].' '.$id;
- $trep['OLDPAGE'] = '---';
- $tdiff = rawWiki($id);
- $hdiff = nl2br(hsc($tdiff));
- }
- $trep['DIFF'] = $tdiff;
- $hrep['DIFF'] = $hdiff;
-
- // send mail
- $mail = new Mailer();
- $mail->to($to);
- $mail->bcc($bcc);
- $mail->subject($subject);
- $mail->setBody($text, $trep, $hrep);
- if($who == 'subscribers') {
- $mail->setHeader(
- 'List-Unsubscribe',
- '<'.wl($id, array('do'=> 'subscribe'), true, '&').'>',
- false
- );
- }
- return $mail->send();
+ $subscription = new Subscription();
+ return $subscription->send_diff($to, $tpl, $id, $rev, $summary);
}
/**
diff --git a/inc/farm.php b/inc/farm.php
index af1035707..54fff3ec6 100644
--- a/inc/farm.php
+++ b/inc/farm.php
@@ -18,7 +18,7 @@
* @author Michael Klier <chi@chimeric.de>
* @author Christopher Smith <chris@jalakai.co.uk>
* @author virtual host part of farm_confpath() based on conf_path() from Drupal.org's /includes/bootstrap.inc
- * (see http://cvs.drupal.org/viewvc/drupal/drupal/includes/bootstrap.inc?view=markup)
+ * (see https://github.com/drupal/drupal/blob/7.x/includes/bootstrap.inc#L537)
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
diff --git a/inc/fulltext.php b/inc/fulltext.php
index eab8850dc..7ee386063 100644
--- a/inc/fulltext.php
+++ b/inc/fulltext.php
@@ -394,10 +394,17 @@ function ft_snippet_re_preprocess($term) {
return $term;
}
- // unicode word boundaries
- // see http://stackoverflow.com/a/2449017/172068
- $BL = '(?<!\pL)';
- $BR = '(?!\pL)';
+ if (UTF8_PROPERTYSUPPORT) {
+ // unicode word boundaries
+ // see http://stackoverflow.com/a/2449017/172068
+ $BL = '(?<!\pL)';
+ $BR = '(?!\pL)';
+ } else {
+ // not as correct as above, but at least won't break
+ $BL = '\b';
+ $BR = '\b';
+ }
+
if(substr($term,0,2) == '\\*'){
$term = substr($term,2);
diff --git a/inc/geshi.php b/inc/geshi.php
index aedc64f84..c6ff9ef77 100644
--- a/inc/geshi.php
+++ b/inc/geshi.php
@@ -41,7 +41,7 @@
//
/** The version of this GeSHi file */
-define('GESHI_VERSION', '1.0.8.10');
+define('GESHI_VERSION', '1.0.8.11');
// Define the root directory for the GeSHi code tree
if (!defined('GESHI_ROOT')) {
@@ -605,6 +605,17 @@ class GeSHi {
}
/**
+ * Returns the version of GeSHi
+ *
+ * @return string
+ * @since 1 0.8.11
+ */
+ function get_version()
+ {
+ return GESHI_VERSION;
+ }
+
+ /**
* Returns an error message associated with the last GeSHi operation,
* or false if no error has occured
*
@@ -808,7 +819,7 @@ class GeSHi {
}
// match the langname
- if (!preg_match('/\'LANG_NAME\'\s*=>\s*\'((?:[^\']|\\\')+)\'/', $data, $matches)) {
+ if (!preg_match('/\'LANG_NAME\'\s*=>\s*\'((?:[^\']|\\\')+?)\'/', $data, $matches)) {
$this->error = sprintf('Geshi::get_lang_fullname(%s): Regex can not detect language', $language);
return false;
}
@@ -1437,6 +1448,8 @@ class GeSHi {
* @todo static?
*/
function get_language_name_from_extension( $extension, $lookup = array() ) {
+ $extension = strtolower($extension);
+
if ( !is_array($lookup) || empty($lookup)) {
$lookup = array(
'6502acme' => array( 'a', 's', 'asm', 'inc' ),
@@ -1470,6 +1483,7 @@ class GeSHi {
'gnuplot' => array('plt'),
'groovy' => array('groovy'),
'haskell' => array('hs'),
+ 'haxe' => array('hx'),
'html4strict' => array('html', 'htm'),
'ini' => array('ini', 'desktop'),
'java' => array('java'),
@@ -1504,6 +1518,7 @@ class GeSHi {
'smalltalk' => array('st'),
'smarty' => array(),
'tcl' => array('tcl'),
+ 'text' => array('txt'),
'vb' => array('bas'),
'vbnet' => array(),
'visualfoxpro' => array(),
@@ -1518,7 +1533,8 @@ class GeSHi {
return $lang;
}
}
- return '';
+
+ return 'text';
}
/**
@@ -1555,6 +1571,9 @@ class GeSHi {
* @since 1.0.0
*/
function add_keyword($key, $word) {
+ if (!is_array($this->language_data['KEYWORDS'][$key])) {
+ $this->language_data['KEYWORDS'][$key] = array();
+ }
if (!in_array($word, $this->language_data['KEYWORDS'][$key])) {
$this->language_data['KEYWORDS'][$key][] = $word;
@@ -1816,7 +1835,7 @@ class GeSHi {
//Decide on which style to use
if ($style === null) { //Check if we should use default style
unset($this->highlight_extra_lines_styles[$lines]);
- } else if ($style === false) { //Check if to remove this line
+ } elseif ($style === false) { //Check if to remove this line
unset($this->highlight_extra_lines[$lines]);
unset($this->highlight_extra_lines_styles[$lines]);
} else {
@@ -1988,7 +2007,7 @@ class GeSHi {
$this->language_data['SYMBOL_DATA'][$symbols] = 0;
if (isset($symbols[1])) { // multiple chars
$symbol_preg_multi[] = preg_quote($symbols, '/');
- } else if ($symbols == '-') {
+ } elseif ($symbols == '-') {
// don't trigger range out of order error
$symbol_preg_single[] = '\-';
} else { // single char
@@ -2392,7 +2411,7 @@ class GeSHi {
foreach ($this->language_data['QUOTEMARKS'] as $quotemark) {
if (!isset($is_string_starter[$quotemark[0]])) {
$is_string_starter[$quotemark[0]] = (string)$quotemark;
- } else if (is_string($is_string_starter[$quotemark[0]])) {
+ } elseif (is_string($is_string_starter[$quotemark[0]])) {
$is_string_starter[$quotemark[0]] = array(
$is_string_starter[$quotemark[0]],
$quotemark);
@@ -2478,7 +2497,7 @@ class GeSHi {
continue;
}
$match_i = $comment_regexp_cache_per_key[$comment_key]['pos'];
- } else if (
+ } elseif (
//This is to allow use of the offset parameter in preg_match and stay as compatible with older PHP versions as possible
(GESHI_PHP_PRE_433 && preg_match($regexp, substr($part, $i), $match, PREG_OFFSET_CAPTURE)) ||
(!GESHI_PHP_PRE_433 && preg_match($regexp, $part, $match, PREG_OFFSET_CAPTURE, $i))
@@ -2586,7 +2605,7 @@ class GeSHi {
continue;
}
$match_i = $escape_regexp_cache_per_key[$escape_key]['pos'];
- } else if (
+ } elseif (
//This is to allow use of the offset parameter in preg_match and stay as compatible with older PHP versions as possible
(GESHI_PHP_PRE_433 && preg_match($regexp, substr($part, $start), $match, PREG_OFFSET_CAPTURE)) ||
(!GESHI_PHP_PRE_433 && preg_match($regexp, $part, $match, PREG_OFFSET_CAPTURE, $start))
@@ -2656,13 +2675,13 @@ class GeSHi {
// don't put a newline around newlines
$string .= "</span>\n";
$start = $es_pos + 2;
- } else if (ord($es_char) >= 128) {
+ } elseif (ord($es_char) >= 128) {
//This is an non-ASCII char (UTF8 or single byte)
//This code tries to work around SF#2037598 ...
if(function_exists('mb_substr')) {
$es_char_m = mb_substr(substr($part, $es_pos+1, 16), 0, 1, $this->encoding);
$string .= $es_char_m . '</span>';
- } else if (!GESHI_PHP_PRE_433 && 'utf-8' == $this->encoding) {
+ } elseif (!GESHI_PHP_PRE_433 && 'utf-8' == $this->encoding) {
if(preg_match("/[\xC2-\xDF][\x80-\xBF]".
"|\xE0[\xA0-\xBF][\x80-\xBF]".
"|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}".
@@ -2684,7 +2703,7 @@ class GeSHi {
$string .= $this->hsc($es_char) . '</span>';
$start = $es_pos + 2;
}
- } else if ($next_escape_regexp_pos < $length &&
+ } elseif ($next_escape_regexp_pos < $length &&
$next_escape_regexp_pos < $close_pos) {
$es_pos = $next_escape_regexp_pos;
//Add the stuff not in the string yet ...
@@ -2728,7 +2747,7 @@ class GeSHi {
$string = '';
$i = $start - 1;
continue;
- } else if ($this->lexic_permissions['STRINGS'] && $hq && $hq[0] == $char &&
+ } elseif ($this->lexic_permissions['STRINGS'] && $hq && $hq[0] == $char &&
substr($part, $i, $hq_strlen) == $hq && ($i != $next_comment_regexp_pos)) {
// The start of a hard quoted string
if (!$this->use_classes) {
@@ -2886,7 +2905,7 @@ class GeSHi {
continue;
}
$match_i = $comment_multi_cache_per_key[$open];
- } else if (($match_i = stripos($part, $open, $i)) !== false) {
+ } elseif (($match_i = stripos($part, $open, $i)) !== false) {
$comment_multi_cache_per_key[$open] = $match_i;
} else {
$comment_multi_cache_per_key[$open] = false;
@@ -2983,7 +3002,7 @@ class GeSHi {
continue;
}
$match_i = $comment_single_cache_per_key[$comment_key];
- } else if (
+ } elseif (
// case sensitive comments
($this->language_data['CASE_SENSITIVE'][GESHI_COMMENTS] &&
($match_i = stripos($part, $comment_mark, $i)) !== false) ||
@@ -3140,10 +3159,10 @@ class GeSHi {
$IN_TAG = false;
}
$lines[$key] .= $char;
- } else if ('<' == $char) {
+ } elseif ('<' == $char) {
$IN_TAG = true;
$lines[$key] .= '<';
- } else if ('&' == $char) {
+ } elseif ('&' == $char) {
$substr = substr($line, $i + 3, 5);
$posi = strpos($substr, ';');
if (false === $posi) {
@@ -3152,7 +3171,7 @@ class GeSHi {
$pos -= $posi+2;
}
$lines[$key] .= $char;
- } else if ("\t" == $char) {
+ } elseif ("\t" == $char) {
$str = '';
// OPTIMISE - move $strs out. Make an array:
// $tabs = array(
@@ -3173,7 +3192,7 @@ class GeSHi {
$lines[$key] .= substr($line, $i + 1);
break;
}
- } else if (0 == $pos && ' ' == $char) {
+ } elseif (0 == $pos && ' ' == $char) {
$lines[$key] .= '&nbsp;';
++$pos;
} else {
@@ -3231,6 +3250,7 @@ class GeSHi {
function handle_keyword_replace($match) {
$k = $this->_kw_replace_group;
$keyword = $match[0];
+ $keyword_match = $match[1];
$before = '';
$after = '';
@@ -3248,12 +3268,12 @@ class GeSHi {
if (!$this->language_data['CASE_SENSITIVE'][$k] &&
strpos($this->language_data['URLS'][$k], '{FNAME}') !== false) {
foreach ($this->language_data['KEYWORDS'][$k] as $word) {
- if (strcasecmp($word, $keyword) == 0) {
+ if (strcasecmp($word, $keyword_match) == 0) {
break;
}
}
} else {
- $word = $keyword;
+ $word = $keyword_match;
}
$before = '<|UR1|"' .
@@ -3367,7 +3387,7 @@ class GeSHi {
foreach (array_keys($this->language_data['KEYWORDS']) as $k) {
if (!isset($this->lexic_permissions['KEYWORDS'][$k]) ||
- $this->lexic_permissions['KEYWORDS'][$k]) {
+ $this->lexic_permissions['KEYWORDS'][$k]) {
$case_sensitive = $this->language_data['CASE_SENSITIVE'][$k];
$modifiers = $case_sensitive ? '' : 'i';
@@ -3991,7 +4011,7 @@ class GeSHi {
$parsed_code .= $this->line_numbers_start + $i;
if ($close) {
$parsed_code .= str_repeat('</span>', $close);
- } else if ($i != $n) {
+ } elseif ($i != $n) {
$parsed_code .= "\n";
}
}
@@ -4123,10 +4143,10 @@ class GeSHi {
if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
if ($this->header_type == GESHI_HEADER_PRE) {
return "<pre$attributes>$header<ol$ol_attributes>";
- } else if ($this->header_type == GESHI_HEADER_DIV ||
+ } elseif ($this->header_type == GESHI_HEADER_DIV ||
$this->header_type == GESHI_HEADER_PRE_VALID) {
return "<div$attributes>$header<ol$ol_attributes>";
- } else if ($this->header_type == GESHI_HEADER_PRE_TABLE) {
+ } elseif ($this->header_type == GESHI_HEADER_PRE_TABLE) {
return "<table$attributes>$header<tbody><tr class=\"li1\">";
}
} else {
diff --git a/inc/html.php b/inc/html.php
index f4e6af663..c8b96cbc0 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -859,7 +859,7 @@ function html_list_index($item){
$base = ':'.$item['id'];
$base = substr($base,strrpos($base,':')+1);
if($item['type']=='d'){
- $ret .= '<a href="'.wl($ID,'idx='.rawurlencode($item['id'])).'" class="idx_dir"><strong>';
+ $ret .= '<a href="'.wl($ID,'idx='.rawurlencode($item['id'])).'" title="' . $item['id'] . '" class="idx_dir"><strong>';
$ret .= $base;
$ret .= '</strong></a>';
}else{
@@ -1154,8 +1154,7 @@ function html_diff($text='',$intro=true,$type=null){
list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev);
}
- $df = new Diff(explode("\n",htmlspecialchars($l_text)),
- explode("\n",htmlspecialchars($r_text)));
+ $df = new Diff(explode("\n",hsc($l_text)),explode("\n",hsc($r_text)));
if($type == 'inline'){
$tdf = new InlineDiffFormatter();
@@ -1205,12 +1204,38 @@ function html_diff($text='',$intro=true,$type=null){
<?php echo $r_head?>
</th>
</tr>
- <?php echo $tdf->format($df)?>
+ <?php echo html_insert_softbreaks($tdf->format($df)); ?>
</table>
</div>
<?php
}
+function html_insert_softbreaks($diffhtml) {
+ // search the diff html string for both:
+ // - html tags, so these can be ignored
+ // - long strings of characters without breaking characters
+ return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/','html_softbreak_callback',$diffhtml);
+}
+
+function html_softbreak_callback($match){
+ // if match is an html tag, return it intact
+ if ($match[0]{0} == '<') return $match[0];
+
+ // its a long string without a breaking character,
+ // make certain characters into breaking characters by inserting a
+ // breaking character (zero length space, U+200B / #8203) in front them.
+ $regex = <<< REGEX
+(?(?= # start a conditional expression with a positive look ahead ...
+&\#?\\w{1,6};) # ... for html entities - we don't want to split them (ok to catch some invalid combinations)
+&\#?\\w{1,6}; # yes pattern - a quicker match for the html entity, since we know we have one
+|
+[?/,&\#;:]+ # no pattern - any other group of 'special' characters to insert a breaking character after
+) # end conditional expression
+REGEX;
+
+ return preg_replace('<'.$regex.'>xu','\0&#8203;',$match[0]);
+}
+
/**
* show warning on conflict detection
*
@@ -1390,8 +1415,7 @@ function html_edit(){
$data = array('form' => $form,
'wr' => $wr,
'media_manager' => true,
- 'target' => ($INPUT->has('target') && $wr &&
- $RANGE !== '') ? $INPUT->str('target') : 'section',
+ 'target' => ($INPUT->has('target') && $wr) ? $INPUT->str('target') : 'section',
'intro_locale' => $include);
if ($data['target'] !== 'section') {
diff --git a/inc/indexer.php b/inc/indexer.php
index f22aee3a0..e518907d7 100644
--- a/inc/indexer.php
+++ b/inc/indexer.php
@@ -102,6 +102,10 @@ function wordlen($w){
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
class Doku_Indexer {
+ /**
+ * @var array $pidCache Cache for getPID()
+ */
+ protected $pidCache = array();
/**
* Adds the contents of a page to the fulltext index
@@ -120,7 +124,7 @@ class Doku_Indexer {
return "locked";
// load known documents
- $pid = $this->addIndexKey('page', '', $page);
+ $pid = $this->getPIDNoLock($page);
if ($pid === false) {
$this->unlock();
return false;
@@ -256,7 +260,7 @@ class Doku_Indexer {
return "locked";
// load known documents
- $pid = $this->addIndexKey('page', '', $page);
+ $pid = $this->getPIDNoLock($page);
if ($pid === false) {
$this->unlock();
return false;
@@ -335,6 +339,109 @@ class Doku_Indexer {
}
/**
+ * Rename a page in the search index without changing the indexed content. This function doesn't check if the
+ * old or new name exists in the filesystem. It returns an error if the old page isn't in the page list of the
+ * indexer and it deletes all previously indexed content of the new page.
+ *
+ * @param string $oldpage The old page name
+ * @param string $newpage The new page name
+ * @return string|bool If the page was successfully renamed, can be a message in the case of an error
+ */
+ public function renamePage($oldpage, $newpage) {
+ if (!$this->lock()) return 'locked';
+
+ $pages = $this->getPages();
+
+ $id = array_search($oldpage, $pages);
+ if ($id === false) {
+ $this->unlock();
+ return 'page is not in index';
+ }
+
+ $new_id = array_search($newpage, $pages);
+ if ($new_id !== false) {
+ // make sure the page is not in the index anymore
+ if ($this->deletePageNoLock($newpage) !== true) {
+ return false;
+ }
+
+ $pages[$new_id] = 'deleted:'.time().rand(0, 9999);
+ }
+
+ $pages[$id] = $newpage;
+
+ // update index
+ if (!$this->saveIndex('page', '', $pages)) {
+ $this->unlock();
+ return false;
+ }
+
+ // reset the pid cache
+ $this->pidCache = array();
+
+ $this->unlock();
+ return true;
+ }
+
+ /**
+ * Renames a meta value in the index. This doesn't change the meta value in the pages, it assumes that all pages
+ * will be updated.
+ *
+ * @param string $key The metadata key of which a value shall be changed
+ * @param string $oldvalue The old value that shall be renamed
+ * @param string $newvalue The new value to which the old value shall be renamed, can exist (then values will be merged)
+ * @return bool|string If renaming the value has been successful, false or error message on error.
+ */
+ public function renameMetaValue($key, $oldvalue, $newvalue) {
+ if (!$this->lock()) return 'locked';
+
+ // change the relation references index
+ $metavalues = $this->getIndex($key, '_w');
+ $oldid = array_search($oldvalue, $metavalues);
+ if ($oldid !== false) {
+ $newid = array_search($newvalue, $metavalues);
+ if ($newid !== false) {
+ // free memory
+ unset ($metavalues);
+
+ // okay, now we have two entries for the same value. we need to merge them.
+ $indexline = $this->getIndexKey($key, '_i', $oldid);
+ if ($indexline != '') {
+ $newindexline = $this->getIndexKey($key, '_i', $newid);
+ $pagekeys = $this->getIndex($key, '_p');
+ $parts = explode(':', $indexline);
+ foreach ($parts as $part) {
+ list($id, $count) = explode('*', $part);
+ $newindexline = $this->updateTuple($newindexline, $id, $count);
+
+ $keyline = explode(':', $pagekeys[$id]);
+ // remove old meta value
+ $keyline = array_diff($keyline, array($oldid));
+ // add new meta value when not already present
+ if (!in_array($newid, $keyline)) {
+ array_push($keyline, $newid);
+ }
+ $pagekeys[$id] = implode(':', $keyline);
+ }
+ $this->saveIndex($key, '_p', $pagekeys);
+ unset($pagekeys);
+ $this->saveIndexKey($key, '_i', $oldid, '');
+ $this->saveIndexKey($key, '_i', $newid, $newindexline);
+ }
+ } else {
+ $metavalues[$oldid] = $newvalue;
+ if (!$this->saveIndex($key, '_w', $metavalues)) {
+ $this->unlock();
+ return false;
+ }
+ }
+ }
+
+ $this->unlock();
+ return true;
+ }
+
+ /**
* Remove a page from the index
*
* Erases entries in all known indexes.
@@ -347,10 +454,26 @@ class Doku_Indexer {
if (!$this->lock())
return "locked";
+ $result = $this->deletePageNoLock($page);
+
+ $this->unlock();
+
+ return $result;
+ }
+
+ /**
+ * Remove a page from the index without locking the index, only use this function if the index is already locked
+ *
+ * Erases entries in all known indexes.
+ *
+ * @param string $page a page name
+ * @return boolean the function completed successfully
+ * @author Tom N Harris <tnharris@whoopdedo.org>
+ */
+ protected function deletePageNoLock($page) {
// load known documents
- $pid = $this->addIndexKey('page', '', $page);
+ $pid = $this->getPIDNoLock($page);
if ($pid === false) {
- $this->unlock();
return false;
}
@@ -376,7 +499,6 @@ class Doku_Indexer {
}
// Save the reverse index
if (!$this->saveIndexKey('pageword', '', $pid, "")) {
- $this->unlock();
return false;
}
@@ -393,6 +515,37 @@ class Doku_Indexer {
$this->saveIndexKey($metaname.'_p', '', $pid, '');
}
+ return true;
+ }
+
+ /**
+ * Clear the whole index
+ *
+ * @return bool If the index has been cleared successfully
+ */
+ public function clear() {
+ global $conf;
+
+ if (!$this->lock()) return false;
+
+ @unlink($conf['indexdir'].'/page.idx');
+ @unlink($conf['indexdir'].'/title.idx');
+ @unlink($conf['indexdir'].'/pageword.idx');
+ @unlink($conf['indexdir'].'/metadata.idx');
+ $dir = @opendir($conf['indexdir']);
+ if($dir!==false){
+ while(($f = readdir($dir)) !== false){
+ if(substr($f,-4)=='.idx' &&
+ (substr($f,0,1)=='i' || substr($f,0,1)=='w'
+ || substr($f,-6)=='_w.idx' || substr($f,-6)=='_i.idx' || substr($f,-6)=='_p.idx'))
+ @unlink($conf['indexdir']."/$f");
+ }
+ }
+ @unlink($conf['indexdir'].'/lengths.idx');
+
+ // clear the pid cache
+ $this->pidCache = array();
+
$this->unlock();
return true;
}
@@ -454,6 +607,58 @@ class Doku_Indexer {
}
/**
+ * Get the numeric PID of a page
+ *
+ * @param string $page The page to get the PID for
+ * @return bool|int The page id on success, false on error
+ */
+ public function getPID($page) {
+ // return PID without locking when it is in the cache
+ if (isset($this->pidCache[$page])) return $this->pidCache[$page];
+
+ if (!$this->lock())
+ return false;
+
+ // load known documents
+ $pid = $this->getPIDNoLock($page);
+ if ($pid === false) {
+ $this->unlock();
+ return false;
+ }
+
+ $this->unlock();
+ return $pid;
+ }
+
+ /**
+ * Get the numeric PID of a page without locking the index.
+ * Only use this function when the index is already locked.
+ *
+ * @param string $page The page to get the PID for
+ * @return bool|int The page id on success, false on error
+ */
+ protected function getPIDNoLock($page) {
+ // avoid expensive addIndexKey operation for the most recently requested pages by using a cache
+ if (isset($this->pidCache[$page])) return $this->pidCache[$page];
+ $pid = $this->addIndexKey('page', '', $page);
+ // limit cache to 10 entries by discarding the oldest element as in DokuWiki usually only the most recently
+ // added item will be requested again
+ if (count($this->pidCache) > 10) array_shift($this->pidCache);
+ $this->pidCache[$page] = $pid;
+ return $pid;
+ }
+
+ /**
+ * Get the page id of a numeric PID
+ *
+ * @param int $pid The PID to get the page id for
+ * @return string The page id
+ */
+ public function getPageFromPID($pid) {
+ return $this->getIndexKey('page', '', $pid);
+ }
+
+ /**
* Find pages in the fulltext index containing the words,
*
* The search words must be pre-tokenized, meaning only letters and
@@ -946,7 +1151,7 @@ class Doku_Indexer {
* @param string $idx name of the index
* @param string $suffix subpart identifier
* @param string $value line to find in the index
- * @return int line number of the value in the index
+ * @return int|bool line number of the value in the index or false if writing the index failed
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
protected function addIndexKey($idx, $suffix, $value) {
@@ -1140,8 +1345,8 @@ class Doku_Indexer {
* @author Tom N Harris <tnharris@whoopdedo.org>
*/
function idx_get_indexer() {
- static $Indexer = null;
- if (is_null($Indexer)) {
+ static $Indexer;
+ if (!isset($Indexer)) {
$Indexer = new Doku_Indexer();
}
return $Indexer;
@@ -1223,6 +1428,12 @@ function idx_addPage($page, $verbose=false, $force=false) {
return $result;
}
+ $Indexer = idx_get_indexer();
+ $pid = $Indexer->getPID($page);
+ if ($pid === false) {
+ if ($verbose) print("Indexer: getting the PID failed for $page".DOKU_LF);
+ return false;
+ }
$body = '';
$metadata = array();
$metadata['title'] = p_get_metadata($page, 'title', METADATA_RENDER_UNLIMITED);
@@ -1230,14 +1441,13 @@ function idx_addPage($page, $verbose=false, $force=false) {
$metadata['relation_references'] = array_keys($references);
else
$metadata['relation_references'] = array();
- $data = compact('page', 'body', 'metadata');
+ $data = compact('page', 'body', 'metadata', 'pid');
$evt = new Doku_Event('INDEXER_PAGE_ADD', $data);
if ($evt->advise_before()) $data['body'] = $data['body'] . " " . rawWiki($page);
$evt->advise_after();
unset($evt);
extract($data);
- $Indexer = idx_get_indexer();
$result = $Indexer->addPageWords($page, $body);
if ($result === "locked") {
if ($verbose) print("Indexer: locked".DOKU_LF);
diff --git a/inc/infoutils.php b/inc/infoutils.php
index 0dc7092ad..92607e4fa 100644
--- a/inc/infoutils.php
+++ b/inc/infoutils.php
@@ -77,7 +77,8 @@ function getVersionData(){
if($date) $version['date'] = $date;
}
}else{
- $version['date'] = 'unknown';
+ global $updateVersion;
+ $version['date'] = 'update version '.$updateVersion;
$version['type'] = 'snapshot?';
}
return $version;
@@ -176,10 +177,10 @@ function check(){
msg('mb_string extension not available - PHP only replacements will be used',0);
}
- if (!preg_match("/^.$/u", "ñ")) {
+ if (!UTF8_PREGSUPPORT) {
msg('PHP is missing UTF-8 support in Perl-Compatible Regular Expressions (PCRE)', -1);
}
- if (!preg_match("/^\pL$/u", "ñ")) {
+ if (!UTF8_PROPERTYSUPPORT) {
msg('PHP is missing Unicode properties support in Perl-Compatible Regular Expressions (PCRE)', -1);
}
diff --git a/inc/lang/ar/lang.php b/inc/lang/ar/lang.php
index 8f34936f3..4928b3dbd 100644
--- a/inc/lang/ar/lang.php
+++ b/inc/lang/ar/lang.php
@@ -92,6 +92,7 @@ $lang['searchmedia_in'] = 'ابحث في %s';
$lang['txt_upload'] = 'اختر ملفاً للرفع';
$lang['txt_filename'] = 'رفع كـ (اختياري)';
$lang['txt_overwrt'] = 'اكتب على ملف موجود';
+$lang['maxuploadsize'] = 'الحجم الاقصى %s للملف';
$lang['lockedby'] = 'مقفلة حاليا لـ';
$lang['lockexpire'] = 'ينتهي القفل في';
$lang['js']['willexpire'] = 'سينتهي قفل تحرير هذه الصفحه خلال دقيقة.\nلتجنب التعارض استخدم زر المعاينة لتصفير مؤقت القفل.';
@@ -190,6 +191,7 @@ $lang['user_tools'] = 'أدوات المستخدم';
$lang['site_tools'] = 'أدوات الموقع';
$lang['page_tools'] = 'أدوات الصفحة';
$lang['skip_to_content'] = 'تجاوز إلى المحتوى';
+$lang['sidebar'] = 'العمود الجانبي';
$lang['mail_newpage'] = 'إضافة صفحة:';
$lang['mail_changed'] = 'تعديل صفحة:';
$lang['mail_subscribe_list'] = 'صفحات غيرت في النطاق:';
diff --git a/inc/lang/ar/mailwrap.html b/inc/lang/ar/mailwrap.html
new file mode 100644
index 000000000..554e34510
--- /dev/null
+++ b/inc/lang/ar/mailwrap.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>@TITLE@</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+
+@HTMLBODY@
+
+<br /><hr />
+<small>تم انشاء هذا البريد الالكتروني بواسطة DokuWiki في @DOKUWIKIURL@.</small>
+</body>
+</html> \ No newline at end of file
diff --git a/inc/lang/ar/subscr_single.txt b/inc/lang/ar/subscr_single.txt
index 5c62aeaeb..611688415 100644
--- a/inc/lang/ar/subscr_single.txt
+++ b/inc/lang/ar/subscr_single.txt
@@ -15,7 +15,7 @@
لإلغاء إشعارات الصفحة,لُج الويكي في
@DOKUWIKIURL@ ثم زُر
-@NEWPAGE@
+@SUBSCRIBE@
وألغ الاشتراك من تغييرات الصفحة و/أو النطاق.
--
diff --git a/inc/lang/az/lang.php b/inc/lang/az/lang.php
index fff6f34b7..6df15a83e 100644
--- a/inc/lang/az/lang.php
+++ b/inc/lang/az/lang.php
@@ -208,8 +208,8 @@ $lang['i_writeerr'] = '<code>%s</code> yaradıla bilmədi. Faylın/qo
$lang['i_badhash'] = 'dokuwiki.php tanıla bilmir və ya dəyişdirilmişdir (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - səhv ya boş qiymətdir';
$lang['i_success'] = 'Konfiqurasiya uğurla başa çatdı. İndi siz install.php faylını silə bilərsiniz.
- <a href="doku.php">Yeni DokuWiki-nizə</a> xoş gəlmişsiniz!';
-$lang['i_failure'] = 'Konfiqurasiya fayllarına məlumat yazan zaman səhvlər tapıldı. Yəgin ki, <a href="doku.php">yeni DokuWiki-nizi</a> istifadə etmədən öncə, Siz o xətaları əl ilə düzəltməli olacaqsınız.';
+ <a href="doku.php?id=wiki:welcome">Yeni DokuWiki-nizə</a> xoş gəlmişsiniz!';
+$lang['i_failure'] = 'Konfiqurasiya fayllarına məlumat yazan zaman səhvlər tapıldı. Yəgin ki, <a href="doku.php?id=wiki:welcome">yeni DokuWiki-nizi</a> istifadə etmədən öncə, Siz o xətaları əl ilə düzəltməli olacaqsınız.';
$lang['i_policy'] = 'İlkin giriş haqları siyasəti';
$lang['i_pol0'] = 'Tam açıq wiki (oxumaq, yazmaq, fayl yükləmək hamıya olar)';
$lang['i_pol1'] = 'Acıq wiki (oxumaq hamıya olar, yazmaq və fayl yükləmək ancaq üzv olan istifadəçilərə olar)';
diff --git a/inc/lang/bg/lang.php b/inc/lang/bg/lang.php
index 3c6c17211..47d83c62f 100644
--- a/inc/lang/bg/lang.php
+++ b/inc/lang/bg/lang.php
@@ -298,10 +298,10 @@ $lang['i_confexists'] = '<code>%s</code> вече съществува'
$lang['i_writeerr'] = '<code>%s</code> не можа да бъде създаден. Трябва да проверите правата за достъп до директорията/файла и да създадете файла ръчно.';
$lang['i_badhash'] = 'Файлът dokuwiki.php не може да бъде разпознат или е променен (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - непозволена или празна стойност';
-$lang['i_success'] = 'Настройването приключи успешно. Вече можете да изтриете файла install.php. Продължете към <a href="doku.php">Вашето ново DokuWiki</a>.';
+$lang['i_success'] = 'Настройването приключи успешно. Вече можете да изтриете файла install.php. Продължете към <a href="doku.php?id=wiki:welcome">Вашето ново DokuWiki</a>.';
-$lang['i_failure'] = 'Възникнаха грешки при записването на файловете с настройки. Вероятно ще се наложи да ги поправите ръчно,
- за да можете да ползвате <a href="doku.php">Вашето ново DokuWiki</a>.';
+$lang['i_failure'] = 'Възникнаха грешки при записването на файловете с настройки. Вероятно ще се наложи да ги поправите ръчно,
+ за да можете да ползвате <a href="doku.php?id=wiki:welcome">Вашето ново DokuWiki</a>.';
$lang['i_policy'] = 'Първоначална политика за достъп';
$lang['i_pol0'] = 'Отворено Wiki (всеки може да чете, пише и качва)';
$lang['i_pol1'] = 'Публично Wiki (всеки може да чете, само регистрирани пишат и качват)';
diff --git a/inc/lang/bg/subscr_single.txt b/inc/lang/bg/subscr_single.txt
index 7b26f8e96..a74a21fb8 100644
--- a/inc/lang/bg/subscr_single.txt
+++ b/inc/lang/bg/subscr_single.txt
@@ -14,7 +14,7 @@
Нова версия: @NEWPAGE@
Ако желаете да прекратите уведомяването за страницата трябва да се впишете на адрес @DOKUWIKIURL@, да посетите
-@NEWPAGE@
+@SUBSCRIBE@
и да прекратите абонамента за промени по страницата или именното пространство.
--
diff --git a/inc/lang/ca-valencia/lang.php b/inc/lang/ca-valencia/lang.php
index e299f6427..532f6c73d 100644
--- a/inc/lang/ca-valencia/lang.php
+++ b/inc/lang/ca-valencia/lang.php
@@ -211,9 +211,9 @@ $lang['i_writeerr'] = 'No es pot crear <code>%s</code>. Haurà de com
$lang['i_badhash'] = 'dokuwiki.php substituït o modificat (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - valor illegal o buit';
$lang['i_success'] = 'La configuració ha finalisat correctament. Ya pot borrar l\'archiu install.php. Passe al
-<a href="doku.php">nou DokuWiki</a>.';
+<a href="doku.php?id=wiki:welcome">nou DokuWiki</a>.';
$lang['i_failure'] = 'Han aparegut alguns erros escrivint els archius de configuració. Deurà arreglar-los manualment abans de que
-puga utilisar el <a href="doku.php">nou DokuWiki</a>.';
+puga utilisar el <a href="doku.php?id=wiki:welcome">nou DokuWiki</a>.';
$lang['i_policy'] = 'Política inicial ACL';
$lang['i_pol0'] = 'Wiki obert (llegir, escriure i enviar tots)';
$lang['i_pol1'] = 'Wiki públic (llegir tots, escriure i enviar només usuaris registrats)';
diff --git a/inc/lang/ca/lang.php b/inc/lang/ca/lang.php
index 3a1412617..cb2b64686 100644
--- a/inc/lang/ca/lang.php
+++ b/inc/lang/ca/lang.php
@@ -5,6 +5,7 @@
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Carles Bellver <carles.bellver@cent.uji.es>
* @author Carles Bellver <carles.bellver@gmail.com>
+ * @author daniel@6temes.cat
*/
$lang['encoding'] = 'utf-8';
$lang['direction'] = 'ltr';
@@ -27,7 +28,7 @@ $lang['btn_revs'] = 'Revisions anteriors';
$lang['btn_recent'] = 'Canvis recents';
$lang['btn_upload'] = 'Penja';
$lang['btn_cancel'] = 'Cancel·la';
-$lang['btn_index'] = 'Índex';
+$lang['btn_index'] = 'Mapa del lloc';
$lang['btn_secedit'] = 'Edita';
$lang['btn_login'] = 'Entra';
$lang['btn_logout'] = 'Surt';
@@ -38,14 +39,15 @@ $lang['btn_back'] = 'Enrere';
$lang['btn_backlink'] = 'Què hi enllaça';
$lang['btn_backtomedia'] = 'Torna a la selecció de fitxers';
$lang['btn_subscribe'] = 'Subscripció a canvis d\'aquesta pàgina';
-$lang['btn_unsubscribe'] = 'Cancel·la subscripció a pàgina';
$lang['btn_profile'] = 'Actualització del perfil';
$lang['btn_reset'] = 'Reinicia';
+$lang['btn_resendpwd'] = 'Estableix una nova contrasenya';
$lang['btn_draft'] = 'Edita esborrany';
$lang['btn_recover'] = 'Recupera esborrany';
$lang['btn_draftdel'] = 'Suprimeix esborrany';
$lang['btn_revert'] = 'Restaura';
$lang['btn_register'] = 'Registra\'m';
+$lang['btn_apply'] = 'Aplica';
$lang['loggedinas'] = 'Heu entrat com';
$lang['user'] = 'Nom d\'usuari';
$lang['pass'] = 'Contrasenya';
@@ -75,6 +77,7 @@ $lang['profnoempty'] = 'No es pot deixar en blanc el nom o l\'adreça
$lang['profchanged'] = 'El perfil d\'usuari s\'ha actualitzat correctament.';
$lang['pwdforget'] = 'Heu oblidat la contrasenya? Podeu obtenir-ne una de nova.';
$lang['resendna'] = 'Aquest wiki no permet tornar a enviar la contrasenya.';
+$lang['resendpwd'] = 'Estableix una nova contrasenya per';
$lang['resendpwdmissing'] = 'Heu d\'emplenar tots els camps.';
$lang['resendpwdnouser'] = 'No s\'ha pogut trobar aquest usuari a la base de dades.';
$lang['resendpwdbadauth'] = 'Aquest codi d\'autenticació no és vàlid. Assegureu-vos d\'utilitzar l\'enllaç de confirmació complet.';
@@ -87,10 +90,52 @@ $lang['searchmedia_in'] = 'Cerca en: %s';
$lang['txt_upload'] = 'Trieu el fitxer que voleu penjar';
$lang['txt_filename'] = 'Introduïu el nom wiki (opcional)';
$lang['txt_overwrt'] = 'Sobreescriu el fitxer actual';
+$lang['maxuploadsize'] = 'Puja com a màxim %s per arxiu.';
$lang['lockedby'] = 'Actualment blocat per:';
$lang['lockexpire'] = 'Venciment del blocatge:';
-$lang['js']['willexpire'] = 'El blocatge per a editar aquesta pàgina venç d\'aquí a un minut.\nUtilitzeu la visualització prèvia per reiniciar el rellotge i evitar conflictes.';
-$lang['js']['notsavedyet'] = "Heu fet canvis que es perdran si no els deseu.\nVoleu continuar?";
+$lang['js']['willexpire'] = 'El blocatge per a editar aquesta pàgina venç d\'aquí a un minut.\nUtilitzeu la visualització prèvia per reiniciar el rellotge i evitar conflictes.';
+$lang['js']['notsavedyet'] = 'Heu fet canvis que es perdran si no els deseu.
+Voleu continuar?';
+$lang['js']['searchmedia'] = 'Cerca fitxers';
+$lang['js']['keepopen'] = 'Manté la finestra oberta';
+$lang['js']['hidedetails'] = 'Oculta detalls';
+$lang['js']['mediatitle'] = 'Propietats de l\'enllaç';
+$lang['js']['mediadisplay'] = 'Tipus d\'enllaç';
+$lang['js']['mediaalign'] = 'Alineació';
+$lang['js']['mediasize'] = 'Mida de la imatge';
+$lang['js']['mediatarget'] = 'Destí de l\'enllaç';
+$lang['js']['mediaclose'] = 'Tanca';
+$lang['js']['mediainsert'] = 'Inserta';
+$lang['js']['mediadisplayimg'] = 'Mostra la imatge';
+$lang['js']['mediadisplaylnk'] = 'Mostra només l\'enllaç';
+$lang['js']['mediasmall'] = 'Versió petita';
+$lang['js']['mediamedium'] = 'Versió mitjana';
+$lang['js']['medialarge'] = 'Versió gran';
+$lang['js']['mediaoriginal'] = 'Versió original';
+$lang['js']['medialnk'] = 'Enllaç a la pàgina de detalls';
+$lang['js']['mediadirect'] = 'Enllaç directe a l\'original';
+$lang['js']['medianolnk'] = 'No hi ha enllaç';
+$lang['js']['medianolink'] = 'No enllacis la imatge';
+$lang['js']['medialeft'] = 'Alinea la imatge a l\'esquerra.';
+$lang['js']['mediaright'] = 'Alinea la imatge a la dreta.';
+$lang['js']['mediacenter'] = 'Alinea la imatge al mig.';
+$lang['js']['medianoalign'] = 'No facis servir alineació.';
+$lang['js']['nosmblinks'] = 'Els enllaços amb recursos compartits de Windows només funcionen amb el Microsoft Internet Explorer.
+Si voleu podeu copiar i enganxar l\'enllaç.';
+$lang['js']['linkwiz'] = 'Auxiliar d\'enllaços';
+$lang['js']['linkto'] = 'Enllaça a:';
+$lang['js']['del_confirm'] = 'Suprimiu aquesta entrada?';
+$lang['js']['restore_confirm'] = 'Vols realment restaurar aquesta versió?';
+$lang['js']['media_diff'] = 'Veure les diferències:';
+$lang['js']['media_diff_both'] = 'Un al costat de l\'altre';
+$lang['js']['media_diff_opacity'] = 'Resalta';
+$lang['js']['media_diff_portions'] = 'Llisca';
+$lang['js']['media_select'] = 'Escull els arxius';
+$lang['js']['media_upload_btn'] = 'Pujar';
+$lang['js']['media_done_btn'] = 'Fet';
+$lang['js']['media_drop'] = 'Arrossega aquí els arxius a pujar';
+$lang['js']['media_cancel'] = 'esborra';
+$lang['js']['media_overwrt'] = 'Sobreescriu els arxius existents';
$lang['rssfailed'] = 'S\'ha produït un error en recollir aquesta alimentació: ';
$lang['nothingfound'] = 'No s\'ha trobat res.';
$lang['mediaselect'] = 'Selecció de fitxers';
@@ -108,14 +153,7 @@ $lang['deletefail'] = 'No s\'ha pogut suprimir el fitxer "%s". Compro
$lang['mediainuse'] = 'No s\'ha pogut suprimir el fitxer "%s". Encara s\'està utilitzant.';
$lang['namespaces'] = 'Espais';
$lang['mediafiles'] = 'Fitxers disponibles en';
-$lang['js']['searchmedia'] = 'Cerca fitxers';
-$lang['js']['keepopen'] = 'Manté la finestra oberta';
-$lang['js']['hidedetails'] = 'Oculta detalls';
-$lang['js']['nosmblinks'] = 'Els enllaços amb recursos compartits de Windows només funcionen amb el Microsoft Internet Explorer.
-Si voleu podeu copiar i enganxar l\'enllaç.';
-$lang['js']['linkwiz'] = 'Auxiliar d\'enllaços';
-$lang['js']['linkto'] = 'Enllaça a:';
-$lang['js']['del_confirm'] = 'Suprimiu aquesta entrada?';
+$lang['accessdenied'] = 'No teniu permís per a veure aquesta pàgina.';
$lang['mediausage'] = 'Utilitzeu la sintaxi següent per referir-vos a aquest enllaç:';
$lang['mediaview'] = 'Mostra el fitxer original';
$lang['mediaroot'] = 'arrel';
@@ -131,6 +169,10 @@ $lang['current'] = 'actual';
$lang['yours'] = 'La vostra versió';
$lang['diff'] = 'Mostra diferències amb la versió actual';
$lang['diff2'] = 'Mostra diferències entre les revisions seleccionades';
+$lang['difflink'] = 'Enllaç a la visualització de la comparació';
+$lang['diff_type'] = 'Veieu les diferències:';
+$lang['diff_inline'] = 'En línia';
+$lang['diff_side'] = 'Un al costat de l\'altre';
$lang['line'] = 'Línia';
$lang['breadcrumb'] = 'Camí';
$lang['youarehere'] = 'Sou aquí';
@@ -143,10 +185,20 @@ $lang['external_edit'] = 'edició externa';
$lang['summary'] = 'Resum d\'edició';
$lang['noflash'] = 'Per a visualitzar aquest contingut necessiteu el <a href="http://www.adobe.com/products/flashplayer/">connector d\'Adobe Flash</a>.';
$lang['download'] = 'Baixa el fragment';
+$lang['tools'] = 'Eines';
+$lang['user_tools'] = 'Eines de l\'usuari';
+$lang['site_tools'] = 'Eines del lloc';
+$lang['page_tools'] = 'Eines de la pàgina';
+$lang['skip_to_content'] = 'salta al contingut';
+$lang['sidebar'] = 'Barra lateral';
$lang['mail_newpage'] = 'pàgina afegida:';
$lang['mail_changed'] = 'pàgina modificada:';
$lang['mail_new_user'] = 'nou usuari:';
$lang['mail_upload'] = 'fitxer penjat:';
+$lang['changes_type'] = 'Veure els canvis de';
+$lang['pages_changes'] = 'Pàgines';
+$lang['media_changes'] = 'Arxius gràfics';
+$lang['both_changes'] = 'Pàgines i arxius gràfics';
$lang['qb_bold'] = 'Negreta';
$lang['qb_italic'] = 'Cursiva';
$lang['qb_underl'] = 'Subratllat';
@@ -187,13 +239,27 @@ $lang['img_copyr'] = 'Copyright';
$lang['img_format'] = 'Format';
$lang['img_camera'] = 'Càmera';
$lang['img_keywords'] = 'Paraules clau';
-$lang['subscribe_success'] = 'S\'ha afegit %s a la llista de subscripcions de %s';
-$lang['subscribe_error'] = 'S\'ha produït un error en afegir %s a la llista de subscripcions de %s';
-$lang['subscribe_noaddress'] = 'No hi ha cap adreça de correu associada al vostre nom d\'usuari. No se us ha pogut afegir a la llista de subscripcions.';
-$lang['unsubscribe_success'] = '%s ha estat suprimit de la llista de subscripcions de %s';
-$lang['unsubscribe_error'] = 'S\'ha produït un error en suprimir %s de la llista de subscripcions de %s';
+$lang['img_width'] = 'Ample';
+$lang['img_height'] = 'Alçada';
+$lang['subscr_subscribe_success'] = 'S\'ha afegit %s a la llista de subscripcions per %s';
+$lang['subscr_subscribe_error'] = 'Hi ha hagut un error a l\'afegir %s a la llista per %s';
+$lang['subscr_subscribe_noaddress'] = 'No hi ha cap adreça associada pel vostre nom d\'usuari, no podeu ser afegit a la llista de subscripcions';
+$lang['subscr_unsubscribe_success'] = 'S\'ha esborrat %s de la llista de subscripcions per %s';
+$lang['subscr_unsubscribe_error'] = 'Hi ha hagut un error a l\'esborrar %s de la llista de subscripcions per %s';
+$lang['subscr_already_subscribed'] = '%s ja està subscrit a %s';
+$lang['subscr_not_subscribed'] = '%s no està subscrit a %s';
+$lang['subscr_m_not_subscribed'] = 'En aquests moments no esteu subscrit a l\'actual pàgina o espai';
+$lang['subscr_m_new_header'] = 'Afegeix subcripció';
+$lang['subscr_m_current_header'] = 'Subscripcions actuals';
+$lang['subscr_m_unsubscribe'] = 'Donar-se de baixa';
+$lang['subscr_m_subscribe'] = 'Donar-se d\'alta';
+$lang['subscr_m_receive'] = 'Rebre';
+$lang['subscr_style_every'] = 'Envia\'m un correu electrònic per a cada canvi';
+$lang['subscr_style_digest'] = 'Envia\'m un correu electrònic amb un resum dels canvis per a cada pàgina (cada %.2f dies)';
+$lang['subscr_style_list'] = 'llistat de pàgines canviades des de l\'últim correu electrònic (cada %.2f dies)';
$lang['authmodfailed'] = 'La configuració de l\'autenticació d\'usuaris és errònia. Informeu els administradors del wiki.';
$lang['authtempfail'] = 'L\'autenticació d\'usuaris no està disponible temporalment. Si aquesta situació persisteix, si us plau informeu els administradors del wiki.';
+$lang['authpwdexpire'] = 'La vostra contrasenya caducarà en %d dies, l\'hauríeu de canviar aviat.';
$lang['i_chooselang'] = 'Trieu l\'idioma';
$lang['i_installer'] = 'Instal·lador de DokuWiki';
$lang['i_wikiname'] = 'Nom del wiki';
@@ -215,6 +281,7 @@ $lang['i_pol0'] = 'Wiki obert (tothom pot llegir, escriure i penj
$lang['i_pol1'] = 'Wiki públic (tothom pot llegir, els usuaris registrats poden escriure i penjar fitxers)';
$lang['i_pol2'] = 'Wiki tancat (només els usuaris registrats poden llegir, escriure i penjar fitxers)';
$lang['i_retry'] = 'Reintenta';
+$lang['i_license'] = 'Escolliu el tipus de llicència que voleu fer servir per al vostre contingut:';
$lang['recent_global'] = 'Esteu veient els canvis recents de l\'espai <strong>%s</strong>. També podeu veure els <a href="%s">canvis recents de tot el wiki</a>.';
$lang['years'] = 'fa %d anys';
$lang['months'] = 'fa %d mesos';
@@ -223,3 +290,27 @@ $lang['days'] = 'fa %d dies';
$lang['hours'] = 'fa %d hores';
$lang['minutes'] = 'fa %d minuts';
$lang['seconds'] = 'fa %d segons';
+$lang['wordblock'] = 'El vostre canvi no s\'ha guardat perquè conté text blocat (spam)';
+$lang['media_uploadtab'] = 'Puja';
+$lang['media_searchtab'] = 'Busca';
+$lang['media_file'] = 'Fitxer';
+$lang['media_viewtab'] = 'Mostra';
+$lang['media_edittab'] = 'Edita';
+$lang['media_historytab'] = 'Històric';
+$lang['media_list_thumbs'] = 'Miniatura';
+$lang['media_list_rows'] = 'Files';
+$lang['media_sort_name'] = 'Nom';
+$lang['media_sort_date'] = 'Data';
+$lang['media_namespaces'] = 'Escolliu l\'espai';
+$lang['media_files'] = 'Arxius a %s';
+$lang['media_upload'] = 'Puja a %s';
+$lang['media_search'] = 'Busca a %s';
+$lang['media_view'] = '%s';
+$lang['media_viewold'] = '%s a %s';
+$lang['media_edit'] = 'Edita %s';
+$lang['media_history'] = 'Històric de %s';
+$lang['media_meta_edited'] = 'metadata editada';
+$lang['media_perm_read'] = 'No teniu permisos suficients per a llegir arxius.';
+$lang['media_perm_upload'] = 'No teniu permisos suficients per a pujar arxius';
+$lang['media_update'] = 'Puja la nova versió';
+$lang['media_restore'] = 'Restaura aquesta versió';
diff --git a/inc/lang/ca/mailwrap.html b/inc/lang/ca/mailwrap.html
new file mode 100644
index 000000000..ed3bb6e9d
--- /dev/null
+++ b/inc/lang/ca/mailwrap.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>@TITLE@</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+
+@HTMLBODY@
+
+<br /><hr />
+<small>Aquest correu electrònic ha estat generat per DokuWiki a @DOKUWIKIURL@.</small>
+</body>
+</html> \ No newline at end of file
diff --git a/inc/lang/ca/resetpwd.txt b/inc/lang/ca/resetpwd.txt
new file mode 100644
index 000000000..565f1d5b0
--- /dev/null
+++ b/inc/lang/ca/resetpwd.txt
@@ -0,0 +1,3 @@
+===== Establiu una nova contrasenya =====
+
+Introdueixi una nova contrasenya pel seu compte a aquest wiki. \ No newline at end of file
diff --git a/inc/lang/ca/subscr_digest.txt b/inc/lang/ca/subscr_digest.txt
new file mode 100644
index 000000000..2b95f97a5
--- /dev/null
+++ b/inc/lang/ca/subscr_digest.txt
@@ -0,0 +1,21 @@
+Hola!
+
+La pàgina @PAGE@ al wiki @TITLE@ ha canviat.
+A continuació podeu veure els canvis:
+
+--------------------------------------------------------
+@DIFF@
+--------------------------------------------------------
+
+Versió anterior: @OLDPAGE@
+Nova versió: @NEWPAGE@
+
+Si voleu cancel·lar les notificacions per a la pàgina, accediu al wiki a
+@DOKUWIKIURL@, visiteu
+@SUBSCRIBE@
+i doneu-vos de baixa dels canvis de la pàgina o de l'espai.
+
+
+--
+Aquest mail ha estat generat per DokuWiki a
+@DOKUWIKIURL@ \ No newline at end of file
diff --git a/inc/lang/ca/subscr_form.txt b/inc/lang/ca/subscr_form.txt
new file mode 100644
index 000000000..d3679454f
--- /dev/null
+++ b/inc/lang/ca/subscr_form.txt
@@ -0,0 +1,3 @@
+===== Gestió de les Subscripcions =====
+
+Aquesta pàgina podeu gestiona les vostres subscripcions per a les pàgines i els espais actuals. \ No newline at end of file
diff --git a/inc/lang/ca/subscr_list.txt b/inc/lang/ca/subscr_list.txt
new file mode 100644
index 000000000..56bcad545
--- /dev/null
+++ b/inc/lang/ca/subscr_list.txt
@@ -0,0 +1,21 @@
+Hola!
+
+Alguna(es) pàgina(es) de l'espai @PAGE@ al wiki @TITLE@ han canviat.
+A continuació podeu veure els canvis:
+
+--------------------------------------------------------
+@DIFF@
+--------------------------------------------------------
+
+Versió anterior: @OLDPAGE@
+Nova versió: @NEWPAGE@
+
+Si voleu cancel·lar les notificacions per a la pàgina, accediu al wiki a
+@DOKUWIKIURL@, visiteu
+@SUBSCRIBE@
+i doneu-vos de baixa dels canvis de la pàgina o de l'espai.
+
+
+--
+Aquest mail ha estat generat per DokuWiki a
+@DOKUWIKIURL@ \ No newline at end of file
diff --git a/inc/lang/cs/lang.php b/inc/lang/cs/lang.php
index a53da327a..af94424ac 100644
--- a/inc/lang/cs/lang.php
+++ b/inc/lang/cs/lang.php
@@ -12,6 +12,7 @@
* @author Vojta Beran <xmamut@email.cz>
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
+ * @author Jakub A. Těšínský (j@kub.cz)
*/
$lang['encoding'] = 'utf-8';
$lang['direction'] = 'ltr';
@@ -197,6 +198,7 @@ $lang['user_tools'] = 'Uživatelské nástroje';
$lang['site_tools'] = 'Nástroje pro tento web';
$lang['page_tools'] = 'Nástroje pro stránku';
$lang['skip_to_content'] = 'jít k obsahu';
+$lang['sidebar'] = 'Postranní lišta';
$lang['mail_newpage'] = 'nová stránka:';
$lang['mail_changed'] = 'změna stránky:';
$lang['mail_subscribe_list'] = 'stránky změněné ve jmenném prostoru:';
@@ -282,8 +284,8 @@ $lang['i_confexists'] = '<code>%s</code> již existuje';
$lang['i_writeerr'] = 'Nelze vytvořit <code>%s</code>. Budete muset zkontrolovat práva k souborům či adresářům a vytvořit tento soubor ručně.';
$lang['i_badhash'] = 'soubor dokuwiki.php (hash=<code>%s</code>) nebyl rozpoznán nebo byl upraven';
$lang['i_badval'] = '<code>%s</code> - neplatná nebo prázdná hodnota';
-$lang['i_success'] = 'Konfigurace byla úspěšně dokončena. Nyní můžete smazat soubor install.php. Pokračujte do <a href="doku.php">své nové DokuWiki</a>.';
-$lang['i_failure'] = 'Vyskytly se nějaké chyby při zápisu do konfiguračních souborů. Budete je nejspíš muset upravit ručně před použitím <a href="doku.php">své nové DokuWiki</a>.';
+$lang['i_success'] = 'Konfigurace byla úspěšně dokončena. Nyní můžete smazat soubor install.php. Pokračujte do <a href="doku.php?id=wiki:welcome">své nové DokuWiki</a>.';
+$lang['i_failure'] = 'Vyskytly se nějaké chyby při zápisu do konfiguračních souborů. Budete je nejspíš muset upravit ručně před použitím <a href="doku.php?id=wiki:welcome">své nové DokuWiki</a>.';
$lang['i_policy'] = 'Úvodní politika ACL';
$lang['i_pol0'] = 'Otevřená wiki (čtení, zápis a upload pro všechny)';
$lang['i_pol1'] = 'Veřejná wiki (čtení pro všechny, zápis a upload pro registrované uživatele)';
diff --git a/inc/lang/da/lang.php b/inc/lang/da/lang.php
index ee8de1bb8..f132c133b 100644
--- a/inc/lang/da/lang.php
+++ b/inc/lang/da/lang.php
@@ -285,8 +285,8 @@ $lang['i_confexists'] = '<code>%s</code> eksisterer allerede';
$lang['i_writeerr'] = 'Kunne ikke oprette <code>%s</code>. Du bliver nød til at tjekke mappe/fil- tilladelserne og oprette filen manuelt.';
$lang['i_badhash'] = 'uigenkendelig eller modificeret dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - ulovlig eller tom værdi';
-$lang['i_success'] = 'Konfigurationen fulførtedes med success. Du kan nu slette install.php filen. Fortsætte til <a href="doku.php">din nye DokuWiki</a>.';
-$lang['i_failure'] = 'Nogle fejl forekom mens konfigurations filerne skulle skrives. Du er mulighvis nød til at fixe dem manuelt før du kan bruge <a href="doku.php">din nye DokuWiki</a>.';
+$lang['i_success'] = 'Konfigurationen fulførtedes med success. Du kan nu slette install.php filen. Fortsætte til <a href="doku.php?id=wiki:welcome">din nye DokuWiki</a>.';
+$lang['i_failure'] = 'Nogle fejl forekom mens konfigurations filerne skulle skrives. Du er mulighvis nød til at fixe dem manuelt før du kan bruge <a href="doku.php?id=wiki:welcome">din nye DokuWiki</a>.';
$lang['i_policy'] = 'Begyndende ACL politik';
$lang['i_pol0'] = 'Åben Wiki (alle kan læse, skrive og uploade)';
$lang['i_pol1'] = 'Offentlig Wiki (alle kan læse, kun registrerede brugere kan skrive og overføre)';
diff --git a/inc/lang/da/subscr_single.txt b/inc/lang/da/subscr_single.txt
index 64b14588c..cdc554513 100644
--- a/inc/lang/da/subscr_single.txt
+++ b/inc/lang/da/subscr_single.txt
@@ -15,7 +15,7 @@ Ny Revision: @NEWPAGE@
For at slå side notifikationer fra, skal du logge ind på
@DOKUWIKIURL@ og besøge
-@NEWPAGE@
+@SUBSCRIBE@
og slå abonnoment for side / navnerum ændringer fra.
--
diff --git a/inc/lang/de-informal/install.html b/inc/lang/de-informal/install.html
index 55239e6db..f0473772c 100644
--- a/inc/lang/de-informal/install.html
+++ b/inc/lang/de-informal/install.html
@@ -1,10 +1,10 @@
-<p>Diese Seite hilft dir bei der Erst-Installation und Konfiguration von
-<a href="http://dokuwiki.org">Dokuwiki</a>. Zusätzliche Informationen zu
+<p>Diese Seite hilft dir bei der Erstinstallation und Konfiguration von
+<a href="http://dokuwiki.org">DokuWiki</a>. Zusätzliche Informationen zu
diesem Installationsskript findest du auf der entsprechenden
<a href="http://dokuwiki.org/installer">Hilfe-Seite</a> (en).</p>
<p>DokuWiki verwendet normale Dateien für das Speichern von Wikiseiten und
-anderen Informationen (Bilder, Suchindizes, alte Versionen, usw.).
+anderen Informationen (Bilder, Suchindizes, alte Versionen usw.).
Um DokuWiki betreiben zu können, <strong>muss</strong> Schreibzugriff auf die
Verzeichnisse bestehen, in denen DokuWiki diese Dateien ablegt. Dieses
Installationsprogramm kann diese Rechte nicht für dich setzen. Du musst dies
@@ -14,7 +14,7 @@ hostest, über FTP oder ein entsprechendes Werkzeug (z.B. cPanel) durchführen.<
<p>Dieses Skript hilft dir beim ersten Einrichten des Zugangsschutzes
(<abbr title="access control list">ACL</abbr>) von DokuWiki, welcher eine
Administratoranmeldung und damit Zugang zum Administrationsmenü ermöglicht.
-Dort kannst du dann weitere Tätigkeiten wie das Installieren von Plugins, das
+Dort kannst du dann weitere Tätigkeiten wie das Installieren von Plugins, dass
Verwalten von Nutzern und das Ändern von Konfigurationseinstellungen durchführen.
Das Nutzen der Zugangskontrolle ist nicht zwingend erforderlich, es erleichtert aber
die Administration von DokuWiki.</p>
diff --git a/inc/lang/de-informal/lang.php b/inc/lang/de-informal/lang.php
index 0558a2a56..3b19f749d 100644
--- a/inc/lang/de-informal/lang.php
+++ b/inc/lang/de-informal/lang.php
@@ -1,6 +1,6 @@
<?php
/**
- * german language file
+ * german informal language file
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
@@ -67,7 +67,7 @@ $lang['user'] = 'Benutzername';
$lang['pass'] = 'Passwort';
$lang['newpass'] = 'Neues Passwort';
$lang['oldpass'] = 'Bestätigen (Altes Passwort)';
-$lang['passchk'] = 'und nochmal';
+$lang['passchk'] = 'Passwort erneut eingeben';
$lang['remember'] = 'Angemeldet bleiben';
$lang['fullname'] = 'Voller Name';
$lang['email'] = 'E-Mail';
@@ -83,7 +83,7 @@ $lang['regsuccess2'] = 'Der neue Nutzer wurde angelegt.';
$lang['regmailfail'] = 'Offenbar ist ein Fehler beim Versenden der Passwortmail aufgetreten. Bitte wende dich an den Wiki-Admin.';
$lang['regbadmail'] = 'Die angegebene Mail-Adresse scheint ungültig zu sein. Falls dies ein Fehler ist, wende dich bitte an den Wiki-Admin.';
$lang['regbadpass'] = 'Die beiden eingegeben Passwörter stimmen nicht überein. Bitte versuche es noch einmal.';
-$lang['regpwmail'] = 'Ihr DokuWiki Passwort';
+$lang['regpwmail'] = 'Ihr DokuWiki-Passwort';
$lang['reghere'] = 'Du hast noch keinen Zugang? Hier registrieren';
$lang['profna'] = 'Änderung des Benutzerprofils in diesem Wiki nicht möglich.';
$lang['profnochange'] = 'Keine Änderungen, nichts zu tun.';
@@ -92,9 +92,9 @@ $lang['profchanged'] = 'Benutzerprofil erfolgreich geändert.';
$lang['pwdforget'] = 'Passwort vergessen? Fordere ein neues an';
$lang['resendna'] = 'Passwörter versenden ist in diesem Wiki nicht möglich.';
$lang['resendpwd'] = 'Neues Passwort setzen für';
-$lang['resendpwdmissing'] = 'Es tut mir Leid, aber du musst alle Felder ausfüllen.';
-$lang['resendpwdnouser'] = 'Es tut mir Leid, aber der Benutzer existiert nicht in unserer Datenbank.';
-$lang['resendpwdbadauth'] = 'Es tut mir Leid, aber dieser Authentifizierungscode ist ungültig. Stelle sicher, dass du den kompletten Bestätigungslink verwendet haben.';
+$lang['resendpwdmissing'] = 'Es tut mir leid, aber du musst alle Felder ausfüllen.';
+$lang['resendpwdnouser'] = 'Es tut mir leid, aber der Benutzer existiert nicht in unserer Datenbank.';
+$lang['resendpwdbadauth'] = 'Es tut mir leid, aber dieser Authentifizierungscode ist ungültig. Stelle sicher, dass du den kompletten Bestätigungslink verwendet haben.';
$lang['resendpwdconfirm'] = 'Ein Bestätigungslink wurde per E-Mail versandt.';
$lang['resendpwdsuccess'] = 'Dein neues Passwort wurde per E-Mail versandt.';
$lang['license'] = 'Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht:';
@@ -137,7 +137,7 @@ $lang['js']['nosmblinks'] = 'Das Verlinken von Windows-Freigaben funktionie
$lang['js']['linkwiz'] = 'Link-Assistent';
$lang['js']['linkto'] = 'Link zu:';
$lang['js']['del_confirm'] = 'Die ausgewählten Dateien wirklich löschen?';
-$lang['js']['restore_confirm'] = 'Wirkliich diese Version wieder herstellen?';
+$lang['js']['restore_confirm'] = 'Wirklich diese Version wiederherstellen?';
$lang['js']['media_diff'] = 'Unterschiede anzeigen:';
$lang['js']['media_diff_both'] = 'Seite für Seite';
$lang['js']['media_diff_opacity'] = 'Überblenden';
@@ -161,7 +161,7 @@ $lang['uploadspam'] = 'Hochladen verweigert: Treffer auf der Spamlist
$lang['uploadxss'] = 'Hochladen verweigert: Daten scheinen Schadcode zu enthalten.';
$lang['uploadsize'] = 'Die hochgeladene Datei war zu groß. (max. %s)';
$lang['deletesucc'] = 'Die Datei "%s" wurde gelöscht.';
-$lang['deletefail'] = '"%s" konnte nicht gelöscht werden. Keine Berechtigung?.';
+$lang['deletefail'] = '"%s" konnte nicht gelöscht werden. Keine Berechtigung?.';
$lang['mediainuse'] = 'Die Datei "%s" wurde nicht gelöscht. Sie wird noch verwendet.';
$lang['namespaces'] = 'Namensräume';
$lang['mediafiles'] = 'Vorhandene Dateien in';
@@ -181,7 +181,7 @@ $lang['current'] = 'aktuell';
$lang['yours'] = 'Deine Version';
$lang['diff'] = 'Zeige Unterschiede zu aktueller Version';
$lang['diff2'] = 'Zeige Unterschiede der ausgewählten Versionen';
-$lang['difflink'] = 'Link zu der Versionshistorie';
+$lang['difflink'] = 'Link zu der Vergleichsansicht';
$lang['diff_type'] = 'Unterschiede anzeigen:';
$lang['diff_inline'] = 'Inline';
$lang['diff_side'] = 'Side by Side';
@@ -196,15 +196,16 @@ $lang['restored'] = 'alte Version wiederhergestellt (%s)';
$lang['external_edit'] = 'Externe Bearbeitung';
$lang['summary'] = 'Zusammenfassung';
$lang['noflash'] = 'Das <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> wird benötigt, um diesen Inhalt anzuzeigen.';
-$lang['download'] = 'Download-Teil';
+$lang['download'] = 'Schnipsel herunterladen';
$lang['tools'] = 'Werkzeuge';
$lang['user_tools'] = 'Benutzer-Werkzeuge';
$lang['site_tools'] = 'Webseiten-Werkzeuge';
$lang['page_tools'] = 'Seiten-Werkzeuge';
$lang['skip_to_content'] = 'zum Inhalt springen';
+$lang['sidebar'] = 'Seitenleiste';
$lang['mail_newpage'] = 'Neue Seite:';
$lang['mail_changed'] = 'Seite geändert:';
-$lang['mail_subscribe_list'] = 'Seite hat sich im Namespace geändert:';
+$lang['mail_subscribe_list'] = 'Geänderte Seiten im Namensraum:';
$lang['mail_new_user'] = 'Neuer Benutzer:';
$lang['mail_upload'] = 'Datei hochgeladen:';
$lang['changes_type'] = 'Änderungen anzeigen von';
@@ -272,14 +273,14 @@ $lang['subscr_style_digest'] = 'E-Mail mit zusammengefasster Übersicht der Se
$lang['subscr_style_list'] = 'Auflistung aller geänderten Seiten seit der letzten E-Mail (alle %.2f Tage)';
$lang['authmodfailed'] = 'Benutzerüberprüfung nicht möglich. Bitte wende dich an den Admin.';
$lang['authtempfail'] = 'Benutzerüberprüfung momentan nicht möglich. Falls das Problem andauert, wende dich an den Admin.';
-$lang['authpwdexpire'] = 'Dein Passwort läuft in %d Tag(en) ab, du solltest es es bald ändern.';
+$lang['authpwdexpire'] = 'Dein Passwort läuft in %d Tag(en) ab. Du solltest es es frühzeitig ändern.';
$lang['i_chooselang'] = 'Wähle deine Sprache';
$lang['i_installer'] = 'DokuWiki-Installation';
$lang['i_wikiname'] = 'Wiki-Name';
$lang['i_enableacl'] = 'Zugangskontrolle (ACL) aktivieren (empfohlen)';
$lang['i_superuser'] = 'Benutzername des Administrators';
$lang['i_problems'] = 'Das Installationsprogramm hat unten aufgeführte Probleme festgestellt, die zunächst behoben werden müssen, bevor du mit der Installation fortfahren kannst.';
-$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Script nur mit einer neuen, unmodifizierten DokuWiki-Installation. Du solltest entweder alle Dateien noch einmal frisch installieren oder die <a href="http://dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
+$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Skript nur mit einer neuen bzw. nicht modifizierten DokuWiki-Installation. Du solltest entweder alle Dateien noch einmal frisch installieren oder die <a href="http://dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
$lang['i_funcna'] = 'Die PHP-Funktion <code>%s</code> ist nicht verfügbar. Unter Umständen wurde sie von deinem Hoster deaktiviert?';
$lang['i_phpver'] = 'Deine PHP-Version <code>%s</code> ist niedriger als die benötigte Version <code>%s</code>. Bitte aktualisiere deine PHP-Installation.';
$lang['i_permfail'] = '<code>%s</code> ist nicht durch DokuWiki beschreibbar. Du musst die Berechtigungen dieses Ordners ändern!';
@@ -287,12 +288,12 @@ $lang['i_confexists'] = '<code>%s</code> existiert bereits';
$lang['i_writeerr'] = '<code>%s</code> konnte nicht erzeugt werden. Du solltest die Verzeichnis-/Datei-Rechte überprüfen und die Datei manuell anlegen.';
$lang['i_badhash'] = 'Unbekannte oder modifizierte dokuwiki.php (Hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - unerlaubter oder leerer Wert';
-$lang['i_success'] = 'Die Konfiguration wurde erfolgreich abgeschlossen. Du kannst jetzt die install.php löschen. Dein <a href="doku.php">neues DokuWiki</a> ist jetzt für dich bereit.';
-$lang['i_failure'] = 'Es sind Fehler beim Schreiben der Konfigurationsdateien aufgetreten. Du musst diese vermutlich von Hand beheben, bevor du dein <a href="doku.php">neues DokuWiki</a> nutzen kannst.';
-$lang['i_policy'] = 'Anfangseinstellung für Zugangskontrolle (ACL)';
-$lang['i_pol0'] = 'Offenes Wiki (lesen, schreiben, hochladen für alle)';
-$lang['i_pol1'] = 'Öffentliches Wiki (lesen für alle, schreiben und hochladen für registrierte Nutzer)';
-$lang['i_pol2'] = 'Geschlossenes Wiki (lesen, schreiben, hochladen nur für registrierte Nutzer)';
+$lang['i_success'] = 'Die Konfiguration wurde erfolgreich abgeschlossen. Du kannst jetzt die install.php löschen. Dein <a href="doku.php?id=wiki:welcome">neues DokuWiki</a> ist jetzt für dich bereit.';
+$lang['i_failure'] = 'Es sind Fehler beim Schreiben der Konfigurationsdateien aufgetreten. Du musst diese von Hand beheben, bevor du dein <a href="doku.php?id=wiki:welcome">neues DokuWiki</a> nutzen kannst.';
+$lang['i_policy'] = 'Anfangseinstellungen der Zugangskontrolle (ACL)';
+$lang['i_pol0'] = 'Offenes Wiki (lesen, schreiben und hochladen für alle Nutzer)';
+$lang['i_pol1'] = 'Öffentliches Wiki (Lesen für alle, Schreiben und Hochladen nur für registrierte Nutzer)';
+$lang['i_pol2'] = 'Geschlossenes Wiki (Lesen, Schreiben und Hochladen nur für registrierte Nutzer)';
$lang['i_retry'] = 'Wiederholen';
$lang['i_license'] = 'Bitte wähle die Lizenz aus unter der die Wiki-Inhalte veröffentlicht werden sollen:';
$lang['recent_global'] = 'Im Moment siehst du die Änderungen im Namensraum <b>%s</b>. Du kannst auch <a href="%s">die Änderungen im gesamten Wiki sehen</a>.';
diff --git a/inc/lang/de-informal/subscr_single.txt b/inc/lang/de-informal/subscr_single.txt
index 3c557bc17..6e3f58b9f 100644
--- a/inc/lang/de-informal/subscr_single.txt
+++ b/inc/lang/de-informal/subscr_single.txt
@@ -15,7 +15,7 @@ Neue Revision: @NEWPAGE@
Um das Abonnement für diese Seite aufzulösen, melde dich im Wiki an
@DOKUWIKIURL@, besuche dann
-@NEWPAGE@
+@SUBSCRIBE@
und klicke auf den Link 'Aboverwaltung'.
--
diff --git a/inc/lang/de/install.html b/inc/lang/de/install.html
index 599eb983b..5af3198d4 100644
--- a/inc/lang/de/install.html
+++ b/inc/lang/de/install.html
@@ -1,10 +1,10 @@
-<p>Diese Seite hilft Ihnen bei der Erst-Installation und Konfiguration von
-<a href="http://dokuwiki.org">Dokuwiki</a>. Zusätzliche Informationen zu
+<p>Diese Seite hilft Ihnen bei der Erstinstallation und Konfiguration von
+<a href="http://dokuwiki.org">DokuWiki</a>. Zusätzliche Informationen zu
diesem Installationsskript finden Sie auf der entsprechenden
<a href="http://dokuwiki.org/installer">Hilfe Seite</a> (en).</p>
<p>DokuWiki verwendet normale Dateien für das Speichern von Wikiseiten und
-anderen Informationen (Bilder, Suchindizes, alte Versionen, usw.).
+anderen Informationen (Bilder, Suchindizes, alte Versionen usw.).
Um DokuWiki betreiben zu können, <strong>muss</strong> Schreibzugriff auf die
Verzeichnisse bestehen, in denen DokuWiki diese Dateien ablegt. Dieses
Installationsprogramm kann diese Rechte nicht für Sie setzen. Sie müssen dies
@@ -14,7 +14,7 @@ hosten, über FTP oder ein entsprechendes Werkzeug (z.B. cPanel) durchführen.</
<p>Dieses Skript hilft Ihnen beim ersten Einrichten des Zugangsschutzes
(<abbr title="access control list">ACL</abbr>) von DokuWiki, welcher eine
Administratoranmeldung und damit Zugang zum Administrationsmenu ermöglicht.
-Dort können Sie dann weitere Tätigkeiten wie das Installieren von Plugins, das
+Dort können Sie dann weitere Tätigkeiten wie das Installieren von Plugins, dass
Verwalten von Nutzern und das Ändern von Konfigurationseinstellungen durchführen.
Das Nutzen der Zugangskontrolle ist nicht zwingend erforderlich, es erleichtert aber
die Administration von DokuWiki.</p>
diff --git a/inc/lang/de/lang.php b/inc/lang/de/lang.php
index 410022a3d..160ea53e8 100644
--- a/inc/lang/de/lang.php
+++ b/inc/lang/de/lang.php
@@ -69,7 +69,7 @@ $lang['user'] = 'Benutzername';
$lang['pass'] = 'Passwort';
$lang['newpass'] = 'Neues Passwort';
$lang['oldpass'] = 'Bestätigen (Altes Passwort)';
-$lang['passchk'] = 'und nochmal';
+$lang['passchk'] = 'Passwort erneut eingeben';
$lang['remember'] = 'Angemeldet bleiben';
$lang['fullname'] = 'Voller Name';
$lang['email'] = 'E-Mail';
@@ -85,7 +85,7 @@ $lang['regsuccess2'] = 'Der neue Nutzer wurde angelegt.';
$lang['regmailfail'] = 'Offenbar ist ein Fehler beim Versenden der Passwort-E-Mail aufgetreten. Bitte wenden Sie sich an den Wiki-Admin.';
$lang['regbadmail'] = 'Die angegebene E-Mail-Adresse scheint ungültig zu sein. Falls dies ein Fehler ist, wenden Sie sich bitte an den Wiki-Admin.';
$lang['regbadpass'] = 'Die beiden eingegeben Passwörter stimmen nicht überein. Bitte versuchen Sie es noch einmal.';
-$lang['regpwmail'] = 'Ihr DokuWiki Passwort';
+$lang['regpwmail'] = 'Ihr DokuWiki-Passwort';
$lang['reghere'] = 'Sie haben noch keinen Zugang? Hier registrieren';
$lang['profna'] = 'Änderung des Benutzerprofils in diesem Wiki nicht möglich.';
$lang['profnochange'] = 'Keine Änderungen, nichts zu tun.';
@@ -94,9 +94,9 @@ $lang['profchanged'] = 'Benutzerprofil erfolgreich geändert.';
$lang['pwdforget'] = 'Passwort vergessen? Fordere ein neues an';
$lang['resendna'] = 'Passwörter versenden ist in diesem Wiki nicht möglich.';
$lang['resendpwd'] = 'Neues Passwort setzen für';
-$lang['resendpwdmissing'] = 'Es tut mir Leid, aber Sie müssen alle Felder ausfüllen.';
-$lang['resendpwdnouser'] = 'Es tut mir Leid, aber der Benutzer existiert nicht in unserer Datenbank.';
-$lang['resendpwdbadauth'] = 'Es tut mir Leid, aber dieser Authentifizierungscode ist ungültig. Stellen Sie sicher, dass Sie den kompletten Bestätigungslink verwendet haben.';
+$lang['resendpwdmissing'] = 'Es tut mir leid, aber Sie müssen alle Felder ausfüllen.';
+$lang['resendpwdnouser'] = 'Es tut mir leid, aber der Benutzer existiert nicht in unserer Datenbank.';
+$lang['resendpwdbadauth'] = 'Es tut mir leid, aber dieser Authentifizierungscode ist ungültig. Stellen Sie sicher, dass Sie den kompletten Bestätigungslink verwendet haben.';
$lang['resendpwdconfirm'] = 'Ein Bestätigungslink wurde per E-Mail versandt.';
$lang['resendpwdsuccess'] = 'Ihr neues Passwort wurde per E-Mail versandt.';
$lang['license'] = 'Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht:';
@@ -139,7 +139,7 @@ $lang['js']['nosmblinks'] = 'Das Verlinken von Windows-Freigaben funktionie
$lang['js']['linkwiz'] = 'Link-Assistent';
$lang['js']['linkto'] = 'Link nach:';
$lang['js']['del_confirm'] = 'Eintrag wirklich löschen?';
-$lang['js']['restore_confirm'] = 'Really restore this version?';
+$lang['js']['restore_confirm'] = 'Wirklich diese Version wiederherstellen?';
$lang['js']['media_diff'] = 'Unterschiede anzeigen:';
$lang['js']['media_diff_both'] = 'Side by Side';
$lang['js']['media_diff_opacity'] = 'Überblenden';
@@ -204,6 +204,7 @@ $lang['user_tools'] = 'Benutzer-Werkzeuge';
$lang['site_tools'] = 'Webseiten-Werkzeuge';
$lang['page_tools'] = 'Seiten-Werkzeuge';
$lang['skip_to_content'] = 'zum Inhalt springen';
+$lang['sidebar'] = 'Seitenleiste';
$lang['mail_newpage'] = 'Neue Seite:';
$lang['mail_changed'] = 'Seite geändert:';
$lang['mail_subscribe_list'] = 'Geänderte Seiten im Namensraum:';
@@ -272,16 +273,16 @@ $lang['subscr_m_receive'] = 'Benachrichtigung';
$lang['subscr_style_every'] = 'E-Mail bei jeder Bearbeitung';
$lang['subscr_style_digest'] = 'Zusammenfassung der Änderungen für jede veränderte Seite (Alle %.2f Tage)';
$lang['subscr_style_list'] = 'Liste der geänderten Seiten (Alle %.2f Tage)';
-$lang['authmodfailed'] = 'Benutzerüberprüfung nicht möglich. Bitte wenden Sie sich an den Systembetreuer.';
-$lang['authtempfail'] = 'Benutzerüberprüfung momentan nicht möglich. Falls das Problem andauert, wenden Sie sich an den Systembetreuer.';
-$lang['authpwdexpire'] = 'Ihr Passwort läuft in %d Tag(en) ab, Sie sollten es bald ändern.';
+$lang['authmodfailed'] = 'Benutzerüberprüfung nicht möglich. Bitte wenden Sie sich an den Admin.';
+$lang['authtempfail'] = 'Benutzerüberprüfung momentan nicht möglich. Falls das Problem andauert, wenden Sie sich an den Admin.';
+$lang['authpwdexpire'] = 'Ihr Passwort läuft in %d Tag(en) ab. Sie sollten es frühzeitig ändern.';
$lang['i_chooselang'] = 'Wählen Sie Ihre Sprache';
$lang['i_installer'] = 'DokuWiki Installation';
$lang['i_wikiname'] = 'Wiki-Name';
$lang['i_enableacl'] = 'Zugangskontrolle (ACL) aktivieren (empfohlen)';
-$lang['i_superuser'] = 'Administrator Benutzername';
+$lang['i_superuser'] = 'Benutzername des Administrators';
$lang['i_problems'] = 'Das Installationsprogramm hat unten aufgeführte Probleme festgestellt, die zunächst behoben werden müssen bevor Sie mit der Installation fortfahren können.';
-$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Script nur mit einer neuen, unmodifizierten DokuWiki Installation. Sie sollten entweder alle Dateien noch einmal frisch installieren oder die <a href="http://dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
+$lang['i_modified'] = 'Aus Sicherheitsgründen arbeitet dieses Skript nur mit einer neuen bzw. nicht modifizierten DokuWiki Installation. Sie sollten entweder alle Dateien noch einmal frisch installieren oder die <a href="http://dokuwiki.org/install">Dokuwiki-Installationsanleitung</a> konsultieren.';
$lang['i_funcna'] = 'Die PHP-Funktion <code>%s</code> ist nicht verfügbar. Unter Umständen wurde sie von Ihrem Hoster deaktiviert?';
$lang['i_phpver'] = 'Ihre PHP-Version <code>%s</code> ist niedriger als die benötigte Version <code>%s</code>. Bitte aktualisieren Sie Ihre PHP-Installation.';
$lang['i_permfail'] = '<code>%s</code> ist nicht durch DokuWiki beschreibbar. Sie müssen die Berechtigungen dieses Ordners ändern!';
@@ -289,12 +290,12 @@ $lang['i_confexists'] = '<code>%s</code> existiert bereits';
$lang['i_writeerr'] = '<code>%s</code> konnte nicht erzeugt werden. Sie sollten die Verzeichnis-/Datei-Rechte überprüfen und die Datei manuell anlegen.';
$lang['i_badhash'] = 'Unbekannte oder modifizierte dokuwiki.php (Hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - unerlaubter oder leerer Wert';
-$lang['i_success'] = 'Die Konfiguration wurde erfolgreich abgeschlossen. Sie können jetzt die install.php löschen. Ihr <a href="doku.php">neues DokuWiki</a> ist jetzt für Sie bereit.';
-$lang['i_failure'] = 'Es sind Fehler beim Schreiben der Konfigurationsdateien aufgetreten. Sie müssen diese vermutlich von Hand beheben, bevor Sie Ihr <a href="doku.php">neues DokuWiki</a> nutzen können.';
-$lang['i_policy'] = 'Anfangseinstellung für Zugangskontrolle (ACL)';
-$lang['i_pol0'] = 'Offenes Wiki (lesen, schreiben, hochladen für alle)';
-$lang['i_pol1'] = 'Öffentliches Wiki (lesen für alle, schreiben und hochladen für registrierte Nutzer)';
-$lang['i_pol2'] = 'Geschlossenes Wiki (lesen, schreiben, hochladen nur für registrierte Nutzer)';
+$lang['i_success'] = 'Die Konfiguration wurde erfolgreich abgeschlossen. Sie können jetzt die install.php löschen. Ihr <a href="doku.php?id=wiki:welcome">neues DokuWiki</a> ist jetzt für Sie bereit.';
+$lang['i_failure'] = 'Es sind Fehler beim Schreiben der Konfigurationsdateien aufgetreten. Sie müssen diese von Hand beheben, bevor Sie Ihr <a href="doku.php?id=wiki:welcome">neues DokuWiki</a> nutzen können.';
+$lang['i_policy'] = 'Anfangseinstellungen der Zugangskontrolle (ACL)';
+$lang['i_pol0'] = 'Offenes Wiki (lesen, schreiben und hochladen für alle Nutzer)';
+$lang['i_pol1'] = 'Öffentliches Wiki (Lesen für alle, Schreiben und Hochladen nur für registrierte Nutzer)';
+$lang['i_pol2'] = 'Geschlossenes Wiki (Lesen, Schreiben und Hochladen nur für registrierte Nutzer)';
$lang['i_retry'] = 'Wiederholen';
$lang['i_license'] = 'Bitte wählen Sie die Lizenz, unter die Sie Ihre Inhalte stellen möchten:';
$lang['recent_global'] = 'Im Moment sehen Sie die Änderungen im Namensraum <b>%s</b>. Sie können auch <a href="%s">die Änderungen im gesamten Wiki sehen</a>.';
@@ -318,8 +319,8 @@ $lang['media_sort_name'] = 'nach Name';
$lang['media_sort_date'] = 'nach Datum';
$lang['media_namespaces'] = 'Namensraum wählen';
$lang['media_files'] = 'Dateien in %s';
-$lang['media_upload'] = 'In den <strong>%s</strong> Namespace hochladen.';
-$lang['media_search'] = 'Im Namespace <strong>%s</strong> suchen.';
+$lang['media_upload'] = 'In den <strong>%s</strong> Namensraum hochladen.';
+$lang['media_search'] = 'Im Namensraum <strong>%s</strong> suchen.';
$lang['media_view'] = '%s';
$lang['media_viewold'] = '%s in %s';
$lang['media_edit'] = '%s bearbeiten';
diff --git a/inc/lang/de/subscr_single.txt b/inc/lang/de/subscr_single.txt
index f3e1cd393..da9914e50 100644
--- a/inc/lang/de/subscr_single.txt
+++ b/inc/lang/de/subscr_single.txt
@@ -15,7 +15,7 @@ Neue Revision: @NEWPAGE@
Um das Abonnement für diese Seite aufzulösen, melden Sie sich im Wiki an
@DOKUWIKIURL@, besuchen dann
-@NEWPAGE@
+@SUBSCRIBE@
und klicken auf die Taste 'Aboverwaltung'.
--
diff --git a/inc/lang/el/lang.php b/inc/lang/el/lang.php
index 443a5061d..55b70074f 100644
--- a/inc/lang/el/lang.php
+++ b/inc/lang/el/lang.php
@@ -8,6 +8,7 @@
* @author Konstantinos Koryllos <koryllos@gmail.com>
* @author George Petsagourakis <petsagouris@gmail.com>
* @author Petros Vidalis <pvidalis@gmail.com>
+ * @author Vasileios Karavasilis vasileioskaravasilis@gmail.com
*/
$lang['encoding'] = 'utf-8';
$lang['direction'] = 'ltr';
@@ -43,6 +44,7 @@ $lang['btn_backtomedia'] = 'Επιστροφή στην επιλογή α
$lang['btn_subscribe'] = 'Εγγραφή σε λήψη ενημερώσεων σελίδας';
$lang['btn_profile'] = 'Επεξεργασία προφίλ';
$lang['btn_reset'] = 'Ακύρωση';
+$lang['btn_resendpwd'] = 'Εισαγωγή νέου κωδικού';
$lang['btn_draft'] = 'Επεξεργασία αυτόματα αποθηκευμένης σελίδας';
$lang['btn_recover'] = 'Επαναφορά αυτόματα αποθηκευμένης σελίδας';
$lang['btn_draftdel'] = 'Διαγραφή αυτόματα αποθηκευμένης σελίδας';
@@ -79,6 +81,7 @@ $lang['profnoempty'] = 'Δεν επιτρέπεται κενό όνο
$lang['profchanged'] = 'Το προφίλ χρήστη τροποποιήθηκε επιτυχώς.';
$lang['pwdforget'] = 'Ξεχάσατε το κωδικό σας; Αποκτήστε νέο.';
$lang['resendna'] = 'Αυτό το wiki δεν υποστηρίζει την εκ\' νέου αποστολή κωδικών.';
+$lang['resendpwd'] = 'Εισαγωγή νέου ωδικού για';
$lang['resendpwdmissing'] = 'Πρέπει να συμπληρώσετε όλα τα πεδία.';
$lang['resendpwdnouser'] = 'Αυτός ο χρήστης δεν υπάρχει στα αρχεία μας.';
$lang['resendpwdbadauth'] = 'Αυτός ο κωδικός ενεργοποίησης δεν είναι έγκυρος.';
@@ -91,6 +94,7 @@ $lang['searchmedia_in'] = 'Αναζήτηση σε %s';
$lang['txt_upload'] = 'Επιλέξτε αρχείο για φόρτωση';
$lang['txt_filename'] = 'Επιλέξτε νέο όνομα αρχείου (προαιρετικό)';
$lang['txt_overwrt'] = 'Αντικατάσταση υπάρχοντος αρχείου';
+$lang['maxuploadsize'] = 'Μέγιστο μέγεθος αρχείου: %s.';
$lang['lockedby'] = 'Προσωρινά κλειδωμένο από';
$lang['lockexpire'] = 'Το κλείδωμα λήγει στις';
$lang['js']['willexpire'] = 'Το κλείδωμά σας για την επεξεργασία αυτής της σελίδας θα λήξει σε ένα λεπτό.\n Για να το ανανεώσετε χρησιμοποιήστε την Προεπισκόπηση.';
@@ -185,6 +189,12 @@ $lang['external_edit'] = 'εξωτερική τροποποίηση';
$lang['summary'] = 'Επεξεργασία σύνοψης';
$lang['noflash'] = 'Το <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> απαιτείται για την προβολή αυτού του στοιχείου.';
$lang['download'] = 'Λήψη Κώδικα';
+$lang['tools'] = 'Εργαλεία';
+$lang['user_tools'] = 'Εργαλεία Χρήστη';
+$lang['site_tools'] = 'Εργαλεία ιστότοπου';
+$lang['page_tools'] = 'Εργαλεία ιστοσελίδας';
+$lang['skip_to_content'] = 'παράληψη περιεχομένων';
+$lang['sidebar'] = 'Sidebar';
$lang['mail_newpage'] = 'σελίδα προστέθηκε:';
$lang['mail_changed'] = 'σελίδα τροποποιήθηκε:';
$lang['mail_subscribe_list'] = 'σελίδες που άλλαξαν στον φάκελο:';
@@ -255,6 +265,7 @@ $lang['subscr_style_digest'] = 'συνοπτικό email αλλαγών της
$lang['subscr_style_list'] = 'λίστα σελίδων με αλλαγές μετά από το τελευταίο email (κάθε %.2f μέρες)';
$lang['authmodfailed'] = 'Κακή ρύθμιση λίστας χρηστών. Παρακαλούμε ενημερώστε τον διαχειριστή του wiki.';
$lang['authtempfail'] = 'Η συνδεση χρηστών είναι απενεργοποιημένη αυτή την στιγμή. Αν αυτό διαρκέσει για πολύ, παρακαλούμε ενημερώστε τον διαχειριστή του wiki.';
+$lang['authpwdexpire'] = 'Ο κωδικός πρόσβασης θα λήξει σε %s ημέρες. Προτείνουμε να τον αλλάξετε σύντομα.';
$lang['i_chooselang'] = 'Επιλογή γλώσσας';
$lang['i_installer'] = 'Οδηγός εγκατάστασης DokuWiki';
$lang['i_wikiname'] = 'Ονομασία wiki';
@@ -289,16 +300,20 @@ $lang['seconds'] = 'πριν %d δευτερόλεπτα';
$lang['wordblock'] = 'Η αλλαγή σας δεν αποθηκεύτηκε γιατί περιείχε spam.';
$lang['media_uploadtab'] = 'Φόρτωση';
$lang['media_searchtab'] = 'Αναζήτηση';
+$lang['media_file'] = 'Αρχείο';
$lang['media_viewtab'] = 'Εμφάνιση';
$lang['media_edittab'] = 'Επεξεργασία';
$lang['media_historytab'] = 'Ιστορικό';
-$lang['media_thumbsview'] = 'Προεπισκόπιση';
-$lang['media_listview'] = 'Λίστα';
-$lang['media_sort'] = 'Ταξινόμιση';
+$lang['media_list_thumbs'] = 'Μικρογραφίες';
+$lang['media_list_rows'] = 'Γραμμές';
$lang['media_sort_name'] = 'ανά όνομα';
$lang['media_sort_date'] = 'ανά ημερομηνία';
+$lang['media_namespaces'] = 'Επιλογή namespace';
+$lang['media_files'] = 'Αρχεία στο %s φάκελο';
$lang['media_upload'] = 'Φόρτωση στο <strong>%s</strong> φάκελο.';
$lang['media_search'] = 'Αναζήτηση στο <strong>%s</strong> φάκελο.';
+$lang['media_view'] = '%s';
+$lang['media_viewold'] = '%s στα %s';
$lang['media_edit'] = 'Επεξεργασία';
$lang['media_history'] = 'Αυτές είναι οι παλαιότερες αναθεωρήσεις του αρχείου.';
$lang['media_meta_edited'] = 'τα μεταδεδομένα επεξεργάστηκαν';
diff --git a/inc/lang/el/mailwrap.html b/inc/lang/el/mailwrap.html
new file mode 100644
index 000000000..b2e655789
--- /dev/null
+++ b/inc/lang/el/mailwrap.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>@TITLE@</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+
+@HTMLBODY@
+
+<br /><hr />
+<small>Το email έχει δημιουργηθεί από το DokuWiki στις @DOKUWIKIURL@.</small>
+</body>
+</html> \ No newline at end of file
diff --git a/inc/lang/el/resetpwd.txt b/inc/lang/el/resetpwd.txt
new file mode 100644
index 000000000..0d26d05fa
--- /dev/null
+++ b/inc/lang/el/resetpwd.txt
@@ -0,0 +1,3 @@
+====== Εισάγετε νέο κωδικό πρόσβασης ======
+
+Παρακαλούμε, εισάγετε έναν νέο κωδικό πρόσβασης για τον λογαριασμό σας. \ No newline at end of file
diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php
index 0e5a9ac3c..144faf4e1 100644
--- a/inc/lang/en/lang.php
+++ b/inc/lang/en/lang.php
@@ -302,15 +302,18 @@ $lang['i_writeerr'] = 'Unable to create <code>%s</code>. You will nee
$lang['i_badhash'] = 'unrecognised or modified dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - illegal or empty value';
$lang['i_success'] = 'The configuration was finished successfully. You may delete the install.php file now. Continue to
- <a href="doku.php">your new DokuWiki</a>.';
+ <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.';
$lang['i_failure'] = 'Some errors occurred while writing the configuration files. You may need to fix them manually before
- you can use <a href="doku.php">your new DokuWiki</a>.';
+ you can use <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.';
$lang['i_policy'] = 'Initial ACL policy';
$lang['i_pol0'] = 'Open Wiki (read, write, upload for everyone)';
$lang['i_pol1'] = 'Public Wiki (read for everyone, write and upload for registered users)';
$lang['i_pol2'] = 'Closed Wiki (read, write, upload for registered users only)';
$lang['i_retry'] = 'Retry';
$lang['i_license'] = 'Please choose the license you want to put your content under:';
+$lang['i_license_none'] = 'Do not show any license information';
+$lang['i_pop_field'] = 'Please, help us to improve the DokuWiki experience:';
+$lang['i_pop_label'] = 'Once a month, send anonymous usage data to the DokuWiki developers';
$lang['recent_global'] = 'You\'re currently watching the changes inside the <b>%s</b> namespace. You can also <a href="%s">view the recent changes of the whole wiki</a>.';
$lang['years'] = '%d years ago';
diff --git a/inc/lang/en/subscr_single.txt b/inc/lang/en/subscr_single.txt
index 673c4c32a..0bc310e04 100644
--- a/inc/lang/en/subscr_single.txt
+++ b/inc/lang/en/subscr_single.txt
@@ -15,7 +15,7 @@ New Revision: @NEWPAGE@
To cancel the page notifications, log into the wiki at
@DOKUWIKIURL@ then visit
-@NEWPAGE@
+@SUBSCRIBE@
and unsubscribe page and/or namespace changes.
--
diff --git a/inc/lang/eo/lang.php b/inc/lang/eo/lang.php
index 5a0b0245f..1c3b6f519 100644
--- a/inc/lang/eo/lang.php
+++ b/inc/lang/eo/lang.php
@@ -281,8 +281,8 @@ $lang['i_confexists'] = '<code>%s</code> jam ekzistas';
$lang['i_writeerr'] = 'Ne eblas krei "<code>%s</code>". Vi bezonas kontroli la permesojn de la dosier(uj)oj kaj mem krej la dosieron.';
$lang['i_badhash'] = 'dokuwiki.php ne estas rekonebla aŭ ĝi estas modifita (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - malvalida aŭ malplena valoro';
-$lang['i_success'] = 'La agordado sukcese kompletiĝis. Vi povas forigi la dosieron nun. Pluiru al <a href="doku.php">via nova DokuWiki</a>.';
-$lang['i_failure'] = 'Kelkaj eraroj okazis dum la konservo de la agordaj dosieroj. Vi devas senpere korekti ilin antaŭ ol vi povos uzi <a href="doku.php">vian novan DokuWiki-on</a>. ';
+$lang['i_success'] = 'La agordado sukcese kompletiĝis. Vi povas forigi la dosieron nun. Pluiru al <a href="doku.php?id=wiki:welcome">via nova DokuWiki</a>.';
+$lang['i_failure'] = 'Kelkaj eraroj okazis dum la konservo de la agordaj dosieroj. Vi devas senpere korekti ilin antaŭ ol vi povos uzi <a href="doku.php?id=wiki:welcome">vian novan DokuWiki-on</a>. ';
$lang['i_policy'] = 'Komenca ACL-a agordo';
$lang['i_pol0'] = 'Malferma Vikio (legi, skribi, alŝuti povas ĉiuj)';
$lang['i_pol1'] = 'Publika Vikio (legi povas ĉiuj, skribi kaj alŝuti povas registritaj uzantoj)';
diff --git a/inc/lang/eo/subscr_single.txt b/inc/lang/eo/subscr_single.txt
index 431fd0251..e4847e8ab 100644
--- a/inc/lang/eo/subscr_single.txt
+++ b/inc/lang/eo/subscr_single.txt
@@ -15,7 +15,7 @@ Nova versio: @NEWPAGE@
Por nuligi la paĝinformojn, ensalutu la vikion ĉe
@DOKUWIKIURL@, poste iru al
-@NEWPAGE@
+@SUBSCRIBE@
kaj malabonu la paĝajn kaj/aŭ nomspacajn ŝanĝojn.
--
diff --git a/inc/lang/es/lang.php b/inc/lang/es/lang.php
index 4c15877e3..20d0284bc 100644
--- a/inc/lang/es/lang.php
+++ b/inc/lang/es/lang.php
@@ -299,8 +299,8 @@ $lang['i_confexists'] = '<code>%s</code> ya existe';
$lang['i_writeerr'] = 'Imposible crear <code>%s</code>. Se necesita que usted controle los permisos del fichero/directorio y que cree el fichero manualmente.';
$lang['i_badhash'] = 'dokuwiki.php no reconocido o modificado (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - valor ilegal o vacío';
-$lang['i_success'] = 'La configuración ha concluido correctamente. Ahora puede eliminar el archivo install.php. Visite <a href="doku.php">su nuevo DokuWiki</a>.';
-$lang['i_failure'] = 'Han ocurrido algunos errores durante la escritura de los ficheros de configuración. Puede ser que necesite corregirlos manualmente antes de poder usar <a href="doku.php">su nuevo DokuWiki</a>.';
+$lang['i_success'] = 'La configuración ha concluido correctamente. Ahora puede eliminar el archivo install.php. Visite <a href="doku.php?id=wiki:welcome">su nuevo DokuWiki</a>.';
+$lang['i_failure'] = 'Han ocurrido algunos errores durante la escritura de los ficheros de configuración. Puede ser que necesite corregirlos manualmente antes de poder usar <a href="doku.php?id=wiki:welcome">su nuevo DokuWiki</a>.';
$lang['i_policy'] = 'Política de ACL inicial';
$lang['i_pol0'] = 'Wiki abierto (leer, escribir y subir archivos para todos)';
$lang['i_pol1'] = 'Wiki público (leer para todos, escribir y subir archivos para usuarios registrados únicamente)';
diff --git a/inc/lang/et/lang.php b/inc/lang/et/lang.php
index 5e5caa1c8..8ae61558a 100644
--- a/inc/lang/et/lang.php
+++ b/inc/lang/et/lang.php
@@ -223,8 +223,8 @@ $lang['i_permfail'] = 'Dokuwiki ei saa kirjutada faili <code>%s</code
$lang['i_confexists'] = '<code>%s</code> on juba olemas';
$lang['i_writeerr'] = 'Faili <code>%s</code> ei lubata tekitada. Kontrolli kataloogi ja faili õigusi.';
$lang['i_badval'] = '<code>%s</code> - lubamatu või tühi väärtus';
-$lang['i_success'] = 'Seadistamine on õnnelikult lõpule viidud. Sa võid nüüd kustutada faili install.php. Alusta oma <a href="doku.php">uue DokuWiki</a> täitmist.';
-$lang['i_failure'] = 'Konfiguratsiooni faili kirjutamisel esines vigu. Võimalik, et pead need käsitsi parandama enne <a href="doku.php">uue DokuWiki</a> täitma asumist.';
+$lang['i_success'] = 'Seadistamine on õnnelikult lõpule viidud. Sa võid nüüd kustutada faili install.php. Alusta oma <a href="doku.php?id=wiki:welcome">uue DokuWiki</a> täitmist.';
+$lang['i_failure'] = 'Konfiguratsiooni faili kirjutamisel esines vigu. Võimalik, et pead need käsitsi parandama enne <a href="doku.php?id=wiki:welcome">uue DokuWiki</a> täitma asumist.';
$lang['i_policy'] = 'Wiki õiguste algne poliitika';
$lang['i_pol0'] = 'Avatud (lugemine, kirjutamine ja üleslaadimine kõigile lubatud)';
$lang['i_pol1'] = 'Avalikuks lugemiseks (lugeda saavad kõik, kirjutada ja üles laadida vaid registreeritud kasutajad)';
diff --git a/inc/lang/eu/lang.php b/inc/lang/eu/lang.php
index 59d9d86fb..5b03dcb97 100644
--- a/inc/lang/eu/lang.php
+++ b/inc/lang/eu/lang.php
@@ -274,8 +274,8 @@ $lang['i_confexists'] = '<code>%s</code> lehendik existitzen da';
$lang['i_writeerr'] = 'Ezin da <code>%s</code> sortu. Direktorioaren/fitxategiaren baimenak egiaztatu eta sortu fitxategia eskuz.';
$lang['i_badhash'] = 'aldatutakoa edo ezezaguna den dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - balioa arauen aurka edo hutsa';
-$lang['i_success'] = 'Konfigurazioa arrakastaz amaitu da. Orain, install.php fitxategia ezabatu dezakezu. Jarraitu ezazu <a href="doku.php">zure DokuWiki berrian</a>.';
-$lang['i_failure'] = 'Akats batzuk gertatu dira konfigurazio fitxategiak idazterakoan. Hauek eskuz konpondu beharra izan dezakezu <a href="doku.php">zure DokuWiki berria</a> erabili ahal izan aurretik.';
+$lang['i_success'] = 'Konfigurazioa arrakastaz amaitu da. Orain, install.php fitxategia ezabatu dezakezu. Jarraitu ezazu <a href="doku.php?id=wiki:welcome">zure DokuWiki berrian</a>.';
+$lang['i_failure'] = 'Akats batzuk gertatu dira konfigurazio fitxategiak idazterakoan. Hauek eskuz konpondu beharra izan dezakezu <a href="doku.php?id=wiki:welcome">zure DokuWiki berria</a> erabili ahal izan aurretik.';
$lang['i_policy'] = 'Hasierako ACL politika';
$lang['i_pol0'] = 'Wiki Irekia (irakurri, idatzi, fitxategiak igo edonorentzat)';
$lang['i_pol1'] = 'Wiki Publikoa (irakurri edonorentzat, idatzi eta fitxategiak igo erregistratutako erabiltzaileentzat)';
diff --git a/inc/lang/fa/lang.php b/inc/lang/fa/lang.php
index fdcdeb1bc..026d6499a 100644
--- a/inc/lang/fa/lang.php
+++ b/inc/lang/fa/lang.php
@@ -285,8 +285,8 @@ $lang['i_confexists'] = '<code>%s</code> پیش‌تر موجود اس
$lang['i_writeerr'] = 'توانایی ایجاد <code>%s</code> نیست. شما باید دسترسی‌های شاخه یا فایل را بررسی کنید و فایل را به طور دستی ایجاد کنید.';
$lang['i_badhash'] = 'فایل dokuwiki.php غیرقابل تشخیص بوده یا تغییر کرده است (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - غیرقانونی و یا مقادیر تهی';
-$lang['i_success'] = 'تنظیمات با موفقیت به پایان رسید. بهتر است فایل install.php رو حذف کنید. برای ادامه <a href="doku.php">این‌جا</a> کلیک کنید.';
-$lang['i_failure'] = 'مشکلاتی در زمان نوشتن فایل تنظیمات پیش آمده است. شما باید این مشکلات را پیش از استفاده از <a href="doku.php">DokuWiki</a> برطرف کنید.';
+$lang['i_success'] = 'تنظیمات با موفقیت به پایان رسید. بهتر است فایل install.php رو حذف کنید. برای ادامه <a href="doku.php?id=wiki:welcome">این‌جا</a> کلیک کنید.';
+$lang['i_failure'] = 'مشکلاتی در زمان نوشتن فایل تنظیمات پیش آمده است. شما باید این مشکلات را پیش از استفاده از <a href="doku.php?id=wiki:welcome">DokuWiki</a> برطرف کنید.';
$lang['i_policy'] = 'کنترل دسترسی‌های اولیه';
$lang['i_pol0'] = 'ویکی باز (همه می‌توانند بخوانند، بنویسند و فایل ارسال کنند)';
$lang['i_pol1'] = 'ویکی عمومی (همه می‌توانند بخوانند، کاربران ثبت شده می‌توانند بنویسند و فایل ارسال کنند)';
diff --git a/inc/lang/fi/lang.php b/inc/lang/fi/lang.php
index 4f5f6f1a2..73eb3d4cc 100644
--- a/inc/lang/fi/lang.php
+++ b/inc/lang/fi/lang.php
@@ -279,8 +279,8 @@ $lang['i_confexists'] = '<code>%s</code> on jo olemassa';
$lang['i_writeerr'] = '<code>%s</code>n luonti epäonnistui. Tarkista hakemiston/tiedoston oikeudet ja luo tiedosto käsin.';
$lang['i_badhash'] = 'tunnistamaton tai muokattu dokuwiki.php (tarkistussumma=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - väärä tai tyhjä arvo';
-$lang['i_success'] = 'Kokoonpano tehty onnistuneesti. Voit poistaa install.php tiedoston. Jatka <a href="doku.php">uuteen DokuWikiisi</a>.';
-$lang['i_failure'] = 'Joitain virheitä tapahtui kirjoitettaessa vaadittavia tiedostoja. Sinun pitää korjata ne käsin ennen kuin voit käyttää <a href="doku.php">uutta DokuWikiäsi</a>.';
+$lang['i_success'] = 'Kokoonpano tehty onnistuneesti. Voit poistaa install.php tiedoston. Jatka <a href="doku.php?id=wiki:welcome">uuteen DokuWikiisi</a>.';
+$lang['i_failure'] = 'Joitain virheitä tapahtui kirjoitettaessa vaadittavia tiedostoja. Sinun pitää korjata ne käsin ennen kuin voit käyttää <a href="doku.php?id=wiki:welcome">uutta DokuWikiäsi</a>.';
$lang['i_policy'] = 'Käyttöoikeuksien oletusmenettelytapa';
$lang['i_pol0'] = 'Avoin Wiki (luku, kirjoitus, tiedostojen lähetys on sallittu kaikille)';
$lang['i_pol1'] = 'Julkinen Wiki (luku kaikilla, kirjoitus ja tiedostojen lähetys rekisteröidyillä käyttäjillä)';
diff --git a/inc/lang/fr/admin.txt b/inc/lang/fr/admin.txt
index 4477a512b..eeeb2317a 100644
--- a/inc/lang/fr/admin.txt
+++ b/inc/lang/fr/admin.txt
@@ -1,4 +1,3 @@
====== Administration ======
-Ci-dessous, vous trouverez une liste des tâches administratives disponibles dans DokuWiki.
-
+Ci-dessous, vous trouverez une liste des tâches d'administration disponibles dans DokuWiki.
diff --git a/inc/lang/fr/adminplugins.txt b/inc/lang/fr/adminplugins.txt
index 42a3538ab..0b2bf18db 100644
--- a/inc/lang/fr/adminplugins.txt
+++ b/inc/lang/fr/adminplugins.txt
@@ -1 +1 @@
-===== Modules supplémentaires ===== \ No newline at end of file
+===== Extensions ===== \ No newline at end of file
diff --git a/inc/lang/fr/backlinks.txt b/inc/lang/fr/backlinks.txt
index 6902b43e3..8e6d27d95 100644
--- a/inc/lang/fr/backlinks.txt
+++ b/inc/lang/fr/backlinks.txt
@@ -1,4 +1,4 @@
====== Pages pointant sur la page en cours ======
-Ceci est la liste des pages qui pointent sur la page en cours.
+Ceci est la liste des pages qui semblent pointer sur la page actuelle.
diff --git a/inc/lang/fr/conflict.txt b/inc/lang/fr/conflict.txt
index 8f527ee21..e34ec9743 100644
--- a/inc/lang/fr/conflict.txt
+++ b/inc/lang/fr/conflict.txt
@@ -1,6 +1,6 @@
-====== Une version plus récente existe déjà ======
+====== Une version plus récente existe ======
-Une version plus récente du document que vous avez modifié existe déjà. Cela se produit lorsqu'un autre utilisateur enregistre le document pendant que vous le modifiez.
+Une version plus récente du document que vous avez modifié existe. Cela se produit lorsqu'un autre utilisateur enregistre une nouvelle version du document alors que vous le modifiez.
Examinez attentivement les différences ci-dessous et décidez quelle version conserver. Si vous choisissez « Enregistrer », votre version sera enregistrée. Cliquez sur « Annuler » pour conserver la version actuelle.
diff --git a/inc/lang/fr/diff.txt b/inc/lang/fr/diff.txt
index 773695d6d..8569f3497 100644
--- a/inc/lang/fr/diff.txt
+++ b/inc/lang/fr/diff.txt
@@ -1,4 +1,4 @@
====== Différences ======
-Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.
+Cette page vous affiche les différences entre la révision choisie et la version actuelle de la page.
diff --git a/inc/lang/fr/draft.txt b/inc/lang/fr/draft.txt
index a48554298..ab383ee2c 100644
--- a/inc/lang/fr/draft.txt
+++ b/inc/lang/fr/draft.txt
@@ -1,6 +1,6 @@
====== Un fichier brouillon a été trouvé ======
-La dernière modification de cette page ne s'est pas terminée proprement. Dokuwiki a enregistré automatiquement un brouillon de votre travail que vous pouvez utiliser pour votre modification. Ci-dessous figurent les données enregistrées lors de votre dernière session.
+La dernière modification de cette page ne s'est pas terminée correctement. DokuWiki a enregistré automatiquement un brouillon de votre travail que vous pouvez utiliser pour votre modification. Ci-dessous figurent les données enregistrées lors de votre dernière session.
-À vous de décider si vous souhaitez //récupérer// votre session de modification passée, //supprimer// le brouillon enregistré automatiquement ou //annuler// le processus d'édition.
+À vous de décider si vous souhaitez //récupérer// votre session de modification précédente, //supprimer// le brouillon enregistré automatiquement ou //annuler// le processus d'édition.
diff --git a/inc/lang/fr/edit.txt b/inc/lang/fr/edit.txt
index e30f1b78b..df8c9fc9e 100644
--- a/inc/lang/fr/edit.txt
+++ b/inc/lang/fr/edit.txt
@@ -1,2 +1,2 @@
-Modifiez cette page et cliquez sur « Enregistrer ». Voyez le [[:wiki:syntax|guide de la mise en page]] pour une aide à propos du formatage. Veuillez ne modifier cette page que si vous pouvez l'**améliorer**. Si vous souhaitez faire des tests, faites vos premiers pas dans le [[:playground:playground|bac à sable]].
+Modifiez cette page et cliquez sur « Enregistrer ». Voyez le [[:wiki:syntax|guide de mise en page]] pour une aide à propos du formatage. Veuillez ne modifier cette page que si vous pouvez l'**améliorer**. Si vous souhaitez faire des tests, faites vos premiers pas dans le [[:playground:playground|bac à sable]].
diff --git a/inc/lang/fr/index.txt b/inc/lang/fr/index.txt
index c66c656ab..15e16734c 100644
--- a/inc/lang/fr/index.txt
+++ b/inc/lang/fr/index.txt
@@ -1,4 +1,4 @@
-====== Index ======
+====== Plan du site ======
-Voici un index de toutes les pages disponibles, triées par [[doku>fr:namespaces|catégorie]].
+Voici un plan du site de toutes les pages disponibles, triées par [[doku>fr:namespaces|catégories]].
diff --git a/inc/lang/fr/install.html b/inc/lang/fr/install.html
index 91c9f2edf..6dcba25dc 100644
--- a/inc/lang/fr/install.html
+++ b/inc/lang/fr/install.html
@@ -1,13 +1,13 @@
-<p>Cette page vous assiste dans la première installation et la
+<p>Cette page vous assiste dans l'installation et la
configuration de <a href="http://dokuwiki.org">DokuWiki</a>.
-Pour plus d'information sur cet installeur, reportez-vous à sa
+Pour plus d'informations sur cet installateur, reportez-vous à sa
<a href="http://dokuwiki.org/installer">page de
documentation</a>.</p>
<p>DokuWiki utilise des fichiers textes ordinaires pour stocker les pages du
wiki et les autres informations associées à ces pages
-(tel que images, index de recherche, anciennes révisions, etc.). Pour fonctionner correctement, DokuWiki <strong>doit</strong> avoir accès en écriture aux différents répertoires qui contiennent ces fichiers. L'installeur n'est pas capable de modifier les permissions sur les répertoires. Ceci doit être effectué directement sur la ligne de commande de votre shell, ou, si vous êtes hébergé, <em>via</em> FTP ou votre panneau de contrôle (tel que cPanel).</p>
+(par exemple, les images, les index de recherche, les anciennes révisions, ...). Pour fonctionner correctement, DokuWiki <strong>doit</strong> avoir accès en écriture aux différents répertoires qui contiennent ces fichiers. Cet installateur n'est pas capable de modifier les autorisations sur les répertoires. Cette opération doit-être effectué directement depuis votre ligne de commande shell, ou, si vous êtes hébergé, <em>via</em> FTP ou votre panneau de contrôle (par exemple cPanel, Plesk, ...).</p>
-<p>Cet installeur va paramétrer votre configuration de DokuWiki pour des <abbr title="Access Control List - Liste de contrôle d'accès">ACL</abbr>, qui permettront l'accès à un identifiant administrateur et l'accès au menu d'administration de DokuWiki pour l'ajout de modules externes (greffons), la gestion d'utilisateurs, la gestion de l'accès aux pages du wiki et les modifications des paramètres de configuration. Il n'est pas nécessaire au fonctionnement de DokuWiki, néanmoins il facilite l'administration de DokuWiki.</p>
+<p>Cet installateur va paramétrer votre configuration de DokuWiki pour des contrôle d'accès (ACL), qui permettront l'accès à un identifiant administrateur et l'accès au menu d'administration de DokuWiki pour l'ajout d'extensions, la gestion d'utilisateurs, la gestion de l'accès aux pages du wiki et les modifications des paramètres de configuration. Les contrôle d'accès ne sont pas nécessaires au fonctionnement de DokuWiki, néanmoins elles facilitent l'administration de DokuWiki.</p>
-<p>Les utilisateurs expérimentés ou ceux nécessitant des paramétrages particuliers devraient se reporter aux liens suivants pour les détails concernant les <a href="http://dokuwiki.org/install">instructions d'installation</a> et les <a href="http://dokuwiki.org/config">paramètres de configuration</a>.</p>
+<p>Les utilisateurs expérimentés ou les utilisateurs possédants des besoins de configurations spécifiques devraient se reporter aux liens suivants pour les détails concernant les <a href="http://dokuwiki.org/install">instructions d'installation</a> et les <a href="http://dokuwiki.org/config">paramètres de configuration</a>.</p>
diff --git a/inc/lang/fr/lang.php b/inc/lang/fr/lang.php
index c4080bc50..a60112bc3 100644
--- a/inc/lang/fr/lang.php
+++ b/inc/lang/fr/lang.php
@@ -25,6 +25,7 @@
* @author skimpax@gmail.com
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
+ * @author Anael Mobilia <contrib@anael.eu>
*/
$lang['encoding'] = 'utf-8';
$lang['direction'] = 'ltr';
@@ -73,17 +74,17 @@ $lang['user'] = 'Utilisateur';
$lang['pass'] = 'Mot de passe';
$lang['newpass'] = 'Nouveau mot de passe';
$lang['oldpass'] = 'Mot de passe actuel';
-$lang['passchk'] = 'Répéter nouveau mot de passe';
+$lang['passchk'] = 'Répétez le mot de passe';
$lang['remember'] = 'Mémoriser';
$lang['fullname'] = 'Nom';
$lang['email'] = 'Adresse de courriel';
$lang['profile'] = 'Profil utilisateur';
$lang['badlogin'] = 'L\'utilisateur ou le mot de passe est incorrect.';
$lang['minoredit'] = 'Modification mineure';
-$lang['draftdate'] = 'Brouillon auto-enregistré le';
+$lang['draftdate'] = 'Brouillon enregistré de manière automatique le';
$lang['nosecedit'] = 'La page a changé entre temps, les informations de la section sont obsolètes ; la page complète a été chargée à la place.';
$lang['regmissing'] = 'Désolé, vous devez remplir tous les champs.';
-$lang['reguexists'] = 'Désolé, ce nom d\'utilisateur est déjà pris.';
+$lang['reguexists'] = 'Désolé, ce nom d\'utilisateur est déjà utilisé.';
$lang['regsuccess'] = 'L\'utilisateur a été créé. Le mot de passe a été expédié par courriel.';
$lang['regsuccess2'] = 'L\'utilisateur a été créé.';
$lang['regmailfail'] = 'Il semble y avoir un problème à l\'envoi du courriel. Contactez l\'administrateur.';
@@ -92,94 +93,94 @@ $lang['regbadpass'] = 'Les deux mots de passe fournis sont différent
$lang['regpwmail'] = 'Votre mot de passe DokuWiki';
$lang['reghere'] = 'Vous n\'avez pas encore de compte ? Enregistrez-vous ici ';
$lang['profna'] = 'Ce wiki ne permet pas de modifier les profils';
-$lang['profnochange'] = 'Pas de changement, rien à faire.';
+$lang['profnochange'] = 'Pas de modification, rien à faire.';
$lang['profnoempty'] = 'Un nom ou une adresse de courriel vide n\'est pas permis.';
$lang['profchanged'] = 'Mise à jour du profil réussie.';
-$lang['pwdforget'] = 'Mot de passe oublié ? Faites-vous envoyer votre mot de passe ';
+$lang['pwdforget'] = 'Mot de passe oublié ? Obtenez-en un nouveau';
$lang['resendna'] = 'Ce wiki ne permet pas le renvoi de mot de passe.';
$lang['resendpwd'] = 'Définir un nouveau mot de passe pour';
$lang['resendpwdmissing'] = 'Désolé, vous devez remplir tous les champs.';
-$lang['resendpwdnouser'] = 'Désolé, cet utilisateur est introuvable dans notre base.';
-$lang['resendpwdbadauth'] = 'Désolé, ce code d\'authentification est invalide. Assurez-vous d\'avoir utilisé le lien de confirmation.';
-$lang['resendpwdconfirm'] = 'Un lien de confirmation vous a été envoyé par courriel.';
+$lang['resendpwdnouser'] = 'Désolé, cet utilisateur n\'existe pas dans notre base de données.';
+$lang['resendpwdbadauth'] = 'Désolé, ce code d\'authentification est invalide. Assurez-vous d\'avoir utilisé le lien de confirmation intégral.';
+$lang['resendpwdconfirm'] = 'Un lien de confirmation vous a été expédié par courriel.';
$lang['resendpwdsuccess'] = 'Votre nouveau mot de passe vous a été expédié par courriel.';
-$lang['license'] = 'Sauf mention contraire, le contenu de ce wiki est placé sous la licence suivante :';
+$lang['license'] = 'Sauf mention contraire, le contenu de ce wiki est placé sous les termes de la licence suivante :';
$lang['licenseok'] = 'Note : En modifiant cette page, vous acceptez que le contenu soit placé sous les termes de la licence suivante :';
$lang['searchmedia'] = 'Chercher le nom de fichier :';
$lang['searchmedia_in'] = 'Chercher dans %s';
$lang['txt_upload'] = 'Sélectionnez un fichier à envoyer ';
-$lang['txt_filename'] = 'Donnez un « wikiname » (optionnel) ';
-$lang['txt_overwrt'] = 'Écraser le fichier cible';
-$lang['maxuploadsize'] = 'Téléverser max. %s par fichier';
+$lang['txt_filename'] = 'Envoyer en tant que (optionnel) ';
+$lang['txt_overwrt'] = 'Écraser le fichier cible (s\'il existe)';
+$lang['maxuploadsize'] = 'Taille d\'envoi maximale : %s par fichier';
$lang['lockedby'] = 'Actuellement bloqué par';
$lang['lockexpire'] = 'Le blocage expire à';
-$lang['js']['willexpire'] = 'Votre verrouillage pour la modification de cette page expire dans une minute.\nPour éviter les conflits, utilisez le bouton « Aperçu » pour réinitialiser le minuteur.';
+$lang['js']['willexpire'] = 'Votre blocage pour la modification de cette page expire dans une minute.\nPour éviter les conflits, utilisez le bouton « Aperçu » pour réinitialiser le minuteur.';
$lang['js']['notsavedyet'] = 'Les modifications non enregistrées seront perdues. Voulez-vous vraiment continuer ?';
$lang['js']['searchmedia'] = 'Chercher des fichiers';
-$lang['js']['keepopen'] = 'Gardez cette fenêtre toujours ouverte';
-$lang['js']['hidedetails'] = 'Masquer détails';
+$lang['js']['keepopen'] = 'Toujours conserver cette fenêtre ouverte';
+$lang['js']['hidedetails'] = 'Masquer les détails';
$lang['js']['mediatitle'] = 'Paramètres de lien';
$lang['js']['mediadisplay'] = 'Type de lien';
$lang['js']['mediaalign'] = 'Alignement';
-$lang['js']['mediasize'] = 'Taille d\'image';
+$lang['js']['mediasize'] = 'Taille de l\'image';
$lang['js']['mediatarget'] = 'Cible du lien';
$lang['js']['mediaclose'] = 'Fermer';
$lang['js']['mediainsert'] = 'Insérer';
$lang['js']['mediadisplayimg'] = 'Afficher l\'image.';
$lang['js']['mediadisplaylnk'] = 'N\'afficher que le lien.';
$lang['js']['mediasmall'] = 'Petite taille';
-$lang['js']['mediamedium'] = 'taille moyenne';
+$lang['js']['mediamedium'] = 'Taille moyenne';
$lang['js']['medialarge'] = 'Grande taille';
-$lang['js']['mediaoriginal'] = 'taille d\'origine';
+$lang['js']['mediaoriginal'] = 'Taille originelle';
$lang['js']['medialnk'] = 'Lien vers la page de détail';
$lang['js']['mediadirect'] = 'Lien direct vers l\'original';
$lang['js']['medianolnk'] = 'Aucun lien';
$lang['js']['medianolink'] = 'Ne pas lier l\'image';
-$lang['js']['medialeft'] = 'Aligner l\'image sur la gauche.';
-$lang['js']['mediaright'] = 'Aligner l\'image sur la droite.';
-$lang['js']['mediacenter'] = 'Centrer l\'image';
+$lang['js']['medialeft'] = 'Aligner l\'image à gauche.';
+$lang['js']['mediaright'] = 'Aligner l\'image à droite.';
+$lang['js']['mediacenter'] = 'Centrer l\'image.';
$lang['js']['medianoalign'] = 'Ne pas aligner.';
$lang['js']['nosmblinks'] = 'Les liens vers les partages Windows ne fonctionnent qu\'avec Microsoft Internet Explorer.\nVous pouvez toujours copier puis coller le lien.';
$lang['js']['linkwiz'] = 'Assistant Lien';
$lang['js']['linkto'] = 'Lien vers :';
-$lang['js']['del_confirm'] = 'Effacer cette entrée ?';
-$lang['js']['restore_confirm'] = 'Voulez vous vraiment restaurer cette version ?';
-$lang['js']['media_diff'] = 'Voir les différences:';
+$lang['js']['del_confirm'] = 'Voulez-vous vraiment effacer ce(s) élément(s) ?';
+$lang['js']['restore_confirm'] = 'Voulez-vous vraiment restaurer cette version ?';
+$lang['js']['media_diff'] = 'Voir les différences :';
$lang['js']['media_diff_both'] = 'Côte à côte';
$lang['js']['media_diff_opacity'] = 'Calque';
$lang['js']['media_diff_portions'] = 'Curseur';
$lang['js']['media_select'] = 'Sélection de fichiers…';
-$lang['js']['media_upload_btn'] = 'Télécharger';
+$lang['js']['media_upload_btn'] = 'Envoyer';
$lang['js']['media_done_btn'] = 'Terminé';
-$lang['js']['media_drop'] = 'Déposez des fichiers ici pour les télécharger';
+$lang['js']['media_drop'] = 'Déposez des fichiers ici pour les envoyer';
$lang['js']['media_cancel'] = 'supprimer';
$lang['js']['media_overwrt'] = 'Écraser les fichiers existants';
$lang['rssfailed'] = 'Une erreur s\'est produite en récupérant ce flux : ';
$lang['nothingfound'] = 'Pas de réponse.';
-$lang['mediaselect'] = 'Sélection de fichier';
+$lang['mediaselect'] = 'Sélection de fichiers';
$lang['fileupload'] = 'Envoi de fichier';
-$lang['uploadsucc'] = 'Téléversement réussi';
-$lang['uploadfail'] = 'Le téléversement n\'a pas réussi. Les permissions sont-elles correctes ?';
-$lang['uploadwrong'] = 'Téléversement refusé. Cette extension de fichier est interdite !';
-$lang['uploadexist'] = 'Le fichier existe. Téléversement avorté.';
-$lang['uploadbadcontent'] = 'Le contenu envoyé ne correspond pas à l\'extension du fichier %s.';
-$lang['uploadspam'] = 'Le téléversement a été bloqué par la liste noire antispam.';
-$lang['uploadxss'] = 'Le téléversement a été bloqué car son contenu est peut-être malveillant.';
-$lang['uploadsize'] = 'Le fichier téléversé était trop gros. (max. %s)';
+$lang['uploadsucc'] = 'Envoi réussi';
+$lang['uploadfail'] = 'L\'envoi a échoué. Les autorisations sont-elles correctes ?';
+$lang['uploadwrong'] = 'Envoi refusé. Cette extension de fichier est interdite !';
+$lang['uploadexist'] = 'Le fichier existe déjà. L\'envoi a été annulé.';
+$lang['uploadbadcontent'] = 'Le contenu envoyé ne correspond pas à l\'extension du fichier (%s).';
+$lang['uploadspam'] = 'L\'envoi a été bloqué par la liste noire de l\'anti-spam.';
+$lang['uploadxss'] = 'L\'envoi a été bloqué car son contenu est peut-être malveillant.';
+$lang['uploadsize'] = 'Le fichier envoyé était trop gros. (max. : %s)';
$lang['deletesucc'] = 'Le fichier « %s » a été effacé.';
-$lang['deletefail'] = 'Le fichier « %s » n\'a pu être effacé, vérifier les permissions.';
-$lang['mediainuse'] = 'Le fichier « %s » n\'a pas été effacé, il est en cours d\'utilisation.';
+$lang['deletefail'] = 'Le fichier « %s » n\'a pas pu être effacé. Vérifiez les autorisations.';
+$lang['mediainuse'] = 'Le fichier « %s » n\'a pas été effacé : il est en toujours utilisé.';
$lang['namespaces'] = 'Catégories';
$lang['mediafiles'] = 'Fichiers disponibles dans';
$lang['accessdenied'] = 'Vous n\'êtes pas autorisé à voir cette page.';
$lang['mediausage'] = 'Utilisez la syntaxe suivante pour faire référence à ce fichier :';
$lang['mediaview'] = 'Afficher le fichier original';
$lang['mediaroot'] = 'racine';
-$lang['mediaupload'] = 'Téléverser un fichier dans la catégorie actuelle. Pour créer des sous-catégories, préfixez le nom du fichier par le nom de la sous-catégorie séparée par un double-point.';
-$lang['mediaextchange'] = 'Extension du fichier changée de .%s en .%s !';
+$lang['mediaupload'] = 'Envoyez un fichier dans la catégorie actuelle. Pour créer des sous-catégories, préfixez en le nom du fichier séparées par un double-point, après avoir choisis le(s) fichier(s). Le(s) fichier(s) peuvent également être envoyé(s) par glisser-déposer (drag & drop)';
+$lang['mediaextchange'] = 'Extension du fichier modifiée de .%s en .%s !';
$lang['reference'] = 'Références pour';
-$lang['ref_inuse'] = 'Le fichier ne peut être effacé car il est utilisé par les pages suivantes :';
-$lang['ref_hidden'] = 'Des références existent dans des pages que vous n\'avez pas la permission de lire';
+$lang['ref_inuse'] = 'Le fichier ne peut être effacé car il est toujours utilisé par les pages suivantes :';
+$lang['ref_hidden'] = 'Des références sont présentes dans des pages que vous ne pouvez pas voir (autorisations insuffisantes)';
$lang['hits'] = 'Occurrences trouvées';
$lang['quickhits'] = 'Pages trouvées ';
$lang['toc'] = 'Table des matières';
@@ -187,7 +188,7 @@ $lang['current'] = 'Version actuelle';
$lang['yours'] = 'Votre version';
$lang['diff'] = 'Différences avec la version actuelle';
$lang['diff2'] = 'Différences entre les versions sélectionnées';
-$lang['difflink'] = 'Lien vers cette vue';
+$lang['difflink'] = 'Lien vers cette vue comparative';
$lang['diff_type'] = 'Voir les différences :';
$lang['diff_inline'] = 'Sur une seule ligne';
$lang['diff_side'] = 'Côte à côte';
@@ -196,18 +197,19 @@ $lang['breadcrumb'] = 'Piste';
$lang['youarehere'] = 'Vous êtes ici';
$lang['lastmod'] = 'Dernière modification';
$lang['by'] = 'par';
-$lang['deleted'] = 'effacée';
+$lang['deleted'] = 'supprimée';
$lang['created'] = 'créée';
-$lang['restored'] = 'ancienne révision restaurée';
+$lang['restored'] = 'ancienne révision (%s) restaurée';
$lang['external_edit'] = 'modification externe';
$lang['summary'] = 'Résumé';
-$lang['noflash'] = 'Le greffon <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash</a> est nécessaire pour afficher ce contenu.';
+$lang['noflash'] = 'L\'<a href="http://www.adobe.com/products/flashplayer/">extension Adobe Flash</a> est nécessaire pour afficher ce contenu.';
$lang['download'] = 'Télécharger un extrait';
$lang['tools'] = 'Outils';
-$lang['user_tools'] = 'Outils d\'utilisateurs';
-$lang['site_tools'] = 'Outils du Site';
-$lang['page_tools'] = 'Outils de la Page';
+$lang['user_tools'] = 'Outils pour utilisateurs';
+$lang['site_tools'] = 'Outils du site';
+$lang['page_tools'] = 'Outils de la page';
$lang['skip_to_content'] = 'Aller au contenu';
+$lang['sidebar'] = 'Panneau latéral';
$lang['mail_newpage'] = 'page ajoutée :';
$lang['mail_changed'] = 'page modifiée :';
$lang['mail_subscribe_list'] = 'pages modifiées dans la catégorie :';
@@ -215,13 +217,13 @@ $lang['mail_new_user'] = 'nouvel utilisateur :';
$lang['mail_upload'] = 'fichier envoyé :';
$lang['changes_type'] = 'Voir les changements';
$lang['pages_changes'] = 'Pages';
-$lang['media_changes'] = 'Fichier multimédias';
+$lang['media_changes'] = 'Fichiers multimédias';
$lang['both_changes'] = 'Pages et fichiers multimédias';
-$lang['qb_bold'] = 'Emphase forte (gras)';
-$lang['qb_italic'] = 'Emphase (italique)';
-$lang['qb_underl'] = 'Souligné';
+$lang['qb_bold'] = 'Gras';
+$lang['qb_italic'] = 'Italique';
+$lang['qb_underl'] = 'Soulignage';
$lang['qb_code'] = 'Code « machine à écrire »';
-$lang['qb_strike'] = 'Texte barré';
+$lang['qb_strike'] = 'Barré';
$lang['qb_h1'] = 'Titre de niveau 1';
$lang['qb_h2'] = 'Titre de niveau 2';
$lang['qb_h3'] = 'Titre de niveau 3';
@@ -237,14 +239,14 @@ $lang['qb_extlink'] = 'Lien externe';
$lang['qb_hr'] = 'Ligne horizontale';
$lang['qb_ol'] = 'Liste numérotée';
$lang['qb_ul'] = 'Liste à puce';
-$lang['qb_media'] = 'Ajouter des images ou d\'autres fichiers';
+$lang['qb_media'] = 'Ajouter des images ou autres fichiers';
$lang['qb_sig'] = 'Insérer une signature';
$lang['qb_smileys'] = 'Émoticones';
$lang['qb_chars'] = 'Caractères spéciaux';
$lang['upperns'] = 'Aller à la catégorie parente';
$lang['admin_register'] = 'Ajouter un nouvel utilisateur';
$lang['metaedit'] = 'Modifier les métadonnées';
-$lang['metasaveerr'] = 'Erreur lors de l\'écriture des métadonnées';
+$lang['metasaveerr'] = 'Erreur lors de l\'enregistrement des métadonnées';
$lang['metasaveok'] = 'Métadonnées enregistrées';
$lang['img_backto'] = 'Retour à';
$lang['img_title'] = 'Titre';
@@ -252,7 +254,7 @@ $lang['img_caption'] = 'Légende';
$lang['img_date'] = 'Date';
$lang['img_fname'] = 'Nom de fichier';
$lang['img_fsize'] = 'Taille';
-$lang['img_artist'] = 'Auteur';
+$lang['img_artist'] = 'Photographe';
$lang['img_copyr'] = 'Copyright';
$lang['img_format'] = 'Format';
$lang['img_camera'] = 'Appareil photo';
@@ -261,47 +263,47 @@ $lang['img_width'] = 'Largeur';
$lang['img_height'] = 'Hauteur';
$lang['img_manager'] = 'Voir dans le gestionnaire de médias';
$lang['subscr_subscribe_success'] = '%s a été ajouté à la liste de souscription de %s';
-$lang['subscr_subscribe_error'] = 'Erreur en ajoutant %s à la liste de souscription de %s';
+$lang['subscr_subscribe_error'] = 'Erreur à l\'ajout de %s à la liste de souscription de %s';
$lang['subscr_subscribe_noaddress'] = 'Il n\'y a pas d\'adresse associée à votre identifiant, vous ne pouvez pas être ajouté à la liste de souscription';
-$lang['subscr_unsubscribe_success'] = '%s a été retiré de la liste de souscription de %s';
-$lang['subscr_unsubscribe_error'] = 'Erreur en retirant %s de la liste de souscription de %s';
+$lang['subscr_unsubscribe_success'] = '%s a été supprimé de la liste de souscription de %s';
+$lang['subscr_unsubscribe_error'] = 'Erreur au retrait de %s de la liste de souscription de %s';
$lang['subscr_already_subscribed'] = '%s est déjà souscrit à %s';
$lang['subscr_not_subscribed'] = '%s n\'est pas souscrit à %s';
-$lang['subscr_m_not_subscribed'] = 'Vous n\'avez pas souscrit pour l\'instant à la page actuelle ou la catégorie';
+$lang['subscr_m_not_subscribed'] = 'Vous n\'avez pas souscrit pour l\'instant à la page actuelle ou à la catégorie';
$lang['subscr_m_new_header'] = 'Ajouter une souscription';
$lang['subscr_m_current_header'] = 'Souscriptions actives';
$lang['subscr_m_unsubscribe'] = 'Annuler la souscription';
$lang['subscr_m_subscribe'] = 'Souscrire';
$lang['subscr_m_receive'] = 'Recevoir';
-$lang['subscr_style_every'] = 'Envoyer un courriel à chaque modification';
+$lang['subscr_style_every'] = 'Recevoir un courriel à chaque modification';
$lang['subscr_style_digest'] = 'Courriel, tous les %.2f jours, résumant les modifications de chaque page';
$lang['subscr_style_list'] = 'Liste des pages modifiées depuis le dernier courriel (tous les %.2f jours)';
-$lang['authmodfailed'] = 'Mauvais paramétrage de l\'authentification. Merci d\'informer l\'administrateur du Wiki.';
-$lang['authtempfail'] = 'L\'authentification est temporairement indisponible. Si cela perdure, merci d\'informer l\'administrateur du Wiki.';
+$lang['authmodfailed'] = 'Mauvais paramétrage de l\'authentification. Merci d\'en informer l\'administrateur du wiki.';
+$lang['authtempfail'] = 'L\'authentification est temporairement indisponible. Si cela perdure, merci d\'en informer l\'administrateur du wiki.';
$lang['authpwdexpire'] = 'Votre mot de passe expirera dans %d jours, vous devriez le changer bientôt.';
$lang['i_chooselang'] = 'Choisissez votre langue';
-$lang['i_installer'] = 'Installeur DokuWiki';
+$lang['i_installer'] = 'Installateur DokuWiki';
$lang['i_wikiname'] = 'Nom du wiki';
-$lang['i_enableacl'] = 'Activer les ACL (recommandé)';
+$lang['i_enableacl'] = 'Activer le contrôle d\'accès (recommandé)';
$lang['i_superuser'] = 'Super-utilisateur';
-$lang['i_problems'] = 'L\'installeur a détecté les problèmes indiqués ci-dessous. Vous ne pouvez poursuivre tant qu\'ils n\'auront pas été corrigés.';
-$lang['i_modified'] = 'Pour des raisons de sécurité ce script ne fonctionne qu\'avec une installation neuve et non modifiée de DokuWiki. Vous devriez ré-extraire les fichiers depuis le paquet téléchargé ou consulter les <a href="http://dokuwiki.org/install">instructions d\'installation de DokuWiki</a>';
-$lang['i_funcna'] = 'La fonction PHP <code>%s</code> n\'est pas disponible. Peut-être que votre hébergeur l\'a désactivée ?';
+$lang['i_problems'] = 'L\'installateur a détecté les problèmes indiqués ci-dessous. Vous ne pouvez pas poursuivre l\'installation tant qu\'ils n\'auront pas été corrigés.';
+$lang['i_modified'] = 'Pour des raisons de sécurité, ce script ne fonctionne qu\'avec une installation neuve et non modifiée de DokuWiki. Vous devriez ré-extraire les fichiers depuis le paquet téléchargé ou consulter les <a href="http://dokuwiki.org/install">instructions d\'installation de DokuWiki</a>';
+$lang['i_funcna'] = 'La fonction PHP <code>%s</code> n\'est pas disponible. Peut-être que votre hébergeur web l\'a désactivée ?';
$lang['i_phpver'] = 'Votre version de PHP (%s) est antérieure à la version requise (%s). Vous devez mettre à jour votre installation de PHP.';
-$lang['i_permfail'] = '<code>%s</code> n\'est pas accessible en écriture pour DokuWiki. Vous devez corriger les permissions de ce répertoire !';
+$lang['i_permfail'] = '<code>%s</code> n\'est pas accessible en écriture pour DokuWiki. Vous devez corriger les autorisations de ce répertoire !';
$lang['i_confexists'] = '<code>%s</code> existe déjà';
-$lang['i_writeerr'] = 'Impossible de créer <code>%s</code>. Vous devez vérifier les permissions des répertoires/fichiers et créer le fichier manuellement.';
+$lang['i_writeerr'] = 'Impossible de créer <code>%s</code>. Vous devez vérifier les autorisations des répertoires/fichiers et créer le fichier manuellement.';
$lang['i_badhash'] = 'dokuwiki.php non reconnu ou modifié (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - valeur interdite ou vide';
-$lang['i_success'] = 'L\'installation s\'est terminée avec succès. Vous pouvez maintenant supprimer le fichier « install.php ». Continuer avec <a href="doku.php">votre nouveau DokuWiki</a>.';
+$lang['i_success'] = 'L\'installation s\'est terminée avec succès. Vous pouvez maintenant supprimer le fichier « install.php ». Continuer avec <a href="doku.php?id=wiki:welcome">votre nouveau DokuWiki</a>.';
$lang['i_failure'] = 'Des erreurs sont survenues lors de l\'écriture des fichiers de configuration. Il vous faudra les corriger manuellement avant de pouvoir utiliser <a href="doku.php">votre nouveau DokuWiki</a>.';
-$lang['i_policy'] = 'Politique d\'ACL initiale';
+$lang['i_policy'] = 'Politique de contrôle d\'accès initiale';
$lang['i_pol0'] = 'Wiki ouvert (lecture, écriture, envoi de fichiers pour tout le monde)';
$lang['i_pol1'] = 'Wiki public (lecture pour tout le monde, écriture et envoi de fichiers pour les utilisateurs enregistrés)';
$lang['i_pol2'] = 'Wiki fermé (lecture, écriture, envoi de fichiers pour les utilisateurs enregistrés uniquement)';
$lang['i_retry'] = 'Réessayer';
-$lang['i_license'] = 'Veuillez choisir la licence sous laquelle placer votre contenu :';
-$lang['recent_global'] = 'Vous êtes actuellement en train de regarder les modifications au sein de la catégorie <strong>%s</strong>. Vous pouvez aussi <a href="%s">voir les récentes modifications sur tout le wiki</a>.';
+$lang['i_license'] = 'Veuillez choisir la licence sous laquelle vous souhaitez placer votre contenu :';
+$lang['recent_global'] = 'Vous êtes actuellement en train de regarder les modifications au sein de la catégorie <strong>%s</strong>. Vous pouvez également <a href="%s">afficher les derniers changements sur l\'ensemble du wiki</a>.';
$lang['years'] = 'il y a %d ans';
$lang['months'] = 'il y a %d mois';
$lang['weeks'] = 'il y a %d semaines';
@@ -309,27 +311,27 @@ $lang['days'] = 'il y a %d jours';
$lang['hours'] = 'il y a %d heures';
$lang['minutes'] = 'il y a %d minutes';
$lang['seconds'] = 'il y a %d secondes';
-$lang['wordblock'] = 'Vos modifications n\'ont pas été sauvegardées parce qu\'elles contiennent des textes non autorisé (spam).';
-$lang['media_uploadtab'] = 'Télécharger';
+$lang['wordblock'] = 'Vos modifications n\'ont pas été enregistrées car elles contiennent du texte non autorisé (spam).';
+$lang['media_uploadtab'] = 'Envoyer';
$lang['media_searchtab'] = 'Rechercher';
$lang['media_file'] = 'Fichier';
$lang['media_viewtab'] = 'Voir';
$lang['media_edittab'] = 'Éditer';
$lang['media_historytab'] = 'Historique';
-$lang['media_list_thumbs'] = 'Aperçus';
+$lang['media_list_thumbs'] = 'Miniatures';
$lang['media_list_rows'] = 'Lignes';
-$lang['media_sort_name'] = 'Tri par nom';
-$lang['media_sort_date'] = 'Tri par date';
-$lang['media_namespaces'] = 'Choisissez un espace de nom';
-$lang['media_files'] = 'Fichiers de %s';
-$lang['media_upload'] = 'Télécharger dans %s.';
-$lang['media_search'] = 'Chercher dans %s.';
+$lang['media_sort_name'] = 'Nom';
+$lang['media_sort_date'] = 'Date';
+$lang['media_namespaces'] = 'Choisissez une catégorie';
+$lang['media_files'] = 'Fichiers dans %s';
+$lang['media_upload'] = 'Envoyer vers %s.';
+$lang['media_search'] = 'Rechercher dans %s.';
$lang['media_view'] = '%s';
$lang['media_viewold'] = '%s dans %s';
$lang['media_edit'] = 'Éditer %s';
$lang['media_history'] = 'Historique de %s';
$lang['media_meta_edited'] = 'métadonnées éditées';
-$lang['media_perm_read'] = 'Désolé, vous n\'avez pas les droits pour lire les fichiers.';
-$lang['media_perm_upload'] = 'Désolé, vous n\'avez pas les droits pour télécharger des fichiers.';
-$lang['media_update'] = 'Télécharger une nouvelle version';
+$lang['media_perm_read'] = 'Désolé, vous n\'avez pas l\'autorisation de voir les fichiers.';
+$lang['media_perm_upload'] = 'Désolé, vous n\'avez pas l\'autorisation d\'envoyer des fichiers.';
+$lang['media_update'] = 'Envoyer une nouvelle version';
$lang['media_restore'] = 'Restaurer cette version';
diff --git a/inc/lang/fr/locked.txt b/inc/lang/fr/locked.txt
index 82cdd7373..fe88b57c8 100644
--- a/inc/lang/fr/locked.txt
+++ b/inc/lang/fr/locked.txt
@@ -1,3 +1,3 @@
====== Page bloquée ======
-Cette page est actuellement bloquée pour modification par un autre utilisateur. Vous devez attendre que l'autre utilisateur ait terminé ou que le blocage de la page expire.
+Cette page est actuellement bloquée pour modification par un autre utilisateur. Vous devez attendre que cet utilisateur ait terminé ou que le blocage de la page expire.
diff --git a/inc/lang/fr/mailtext.txt b/inc/lang/fr/mailtext.txt
index 3c2d53292..3f191756a 100644
--- a/inc/lang/fr/mailtext.txt
+++ b/inc/lang/fr/mailtext.txt
@@ -14,5 +14,5 @@ Utilisateur : @USER@
--
-Ce courriel a été généré par DokuWiki
+Ce courriel a été généré par DokuWiki depuis
@DOKUWIKIURL@
diff --git a/inc/lang/fr/mailwrap.html b/inc/lang/fr/mailwrap.html
index 2b674196b..aa5011021 100644
--- a/inc/lang/fr/mailwrap.html
+++ b/inc/lang/fr/mailwrap.html
@@ -8,6 +8,6 @@
@HTMLBODY@
<br /><hr />
-<small>Ce courriel a été automatiquement généré par DokuWiki à l'adresse @DOKUWIKIURL@.</small>
+<small>Ce courriel a été automatiquement généré par DokuWiki depuis @DOKUWIKIURL@.</small>
</body>
</html> \ No newline at end of file
diff --git a/inc/lang/fr/newpage.txt b/inc/lang/fr/newpage.txt
index 0ed2b25af..b23bf4fe4 100644
--- a/inc/lang/fr/newpage.txt
+++ b/inc/lang/fr/newpage.txt
@@ -1,4 +1,4 @@
====== Cette page n'existe pas encore ======
-Vous avez suivi un lien vers une page qui n'existe pas encore. Si vos droits sont suffisants, vous pouvez utiliser le bouton ou le lien « Créer cette page ».
+Vous avez suivi un lien vers une page qui n'existe pas encore. Si vos autorisations sont suffisants, vous pouvez la créer en cliquant sur « Créer cette page ».
diff --git a/inc/lang/fr/norev.txt b/inc/lang/fr/norev.txt
index 3f96b6aff..0d40dbe05 100644
--- a/inc/lang/fr/norev.txt
+++ b/inc/lang/fr/norev.txt
@@ -1,4 +1,4 @@
====== Révision non trouvée ======
-La révision demandée n'existe pas. Utilisez le bouton ou le lien « Anciennes révisions » pour une liste des révisions de ce document.
+La révision demandée n'existe pas. Cliquez sur « Anciennes révisions » pour obtenir une liste des révisions de ce document.
diff --git a/inc/lang/fr/password.txt b/inc/lang/fr/password.txt
index f4500fc85..47cb391d2 100644
--- a/inc/lang/fr/password.txt
+++ b/inc/lang/fr/password.txt
@@ -6,5 +6,5 @@ Utilisateur : @LOGIN@
Mot de passe : @PASSWORD@
--
-Ce courriel a été envoyé par DokuWiki de
+Ce courriel a été envoyé par DokuWiki depuis
@DOKUWIKIURL@
diff --git a/inc/lang/fr/preview.txt b/inc/lang/fr/preview.txt
index 26fbcd9c2..00f09e218 100644
--- a/inc/lang/fr/preview.txt
+++ b/inc/lang/fr/preview.txt
@@ -1,4 +1,4 @@
====== Aperçu ======
-Ceci est un aperçu de votre document. Attention ! Il n'est **pas encore enregistré** !
+Ceci est un aperçu de votre document. Attention : il n'est **pas encore enregistré** !
diff --git a/inc/lang/fr/pwconfirm.txt b/inc/lang/fr/pwconfirm.txt
index af84833df..5cbfb2241 100644
--- a/inc/lang/fr/pwconfirm.txt
+++ b/inc/lang/fr/pwconfirm.txt
@@ -1,15 +1,15 @@
Bonjour @FULLNAME@ !
Quelqu'un a demandé un nouveau mot de passe pour votre identifiant
-@TITLE@ sur @DOKUWIKIURL@
+@TITLE@ depuis @DOKUWIKIURL@
Si vous n'êtes pas à l'origine de cette requête d'un nouveau mot de
-passe, ignorez ce message.
+passe, ignorez simplement ce message.
-Pour confirmer que cette requête émane bien de vous, merci de suivre le lien ci-dessous.
+Pour confirmer que cette requête émane bien de vous, merci de cliquer sur le lien ci-dessous.
@CONFIRM@
--
-Ce courriel a été généré par DokuWiki
+Ce courriel a été généré par DokuWiki depuis
@DOKUWIKIURL@
diff --git a/inc/lang/fr/read.txt b/inc/lang/fr/read.txt
index faa756e8b..6afb864a8 100644
--- a/inc/lang/fr/read.txt
+++ b/inc/lang/fr/read.txt
@@ -1,2 +1,2 @@
-Cette page est en lecture seule. Vous pouvez afficher le texte source, mais pas le modifier. Contactez votre administrateur si vous pensez qu'il s'agit d'une erreur.
+Cette page est en lecture seule. Vous pouvez afficher le texte source, mais ne pourrez pas le modifier. Contactez votre administrateur si vous pensez qu'il s'agit d'une erreur.
diff --git a/inc/lang/fr/register.txt b/inc/lang/fr/register.txt
index e2d02f55c..f98383454 100644
--- a/inc/lang/fr/register.txt
+++ b/inc/lang/fr/register.txt
@@ -1,3 +1,3 @@
====== S'enregistrer comme nouvel utilisateur ======
-Remplissez toutes les informations ci-dessous pour vous créer un compte sur ce Wiki. Assurez-vous de fournir une **adresse de courriel valide** car votre mot de passe sera envoyé à cette adresse. Le nom d'utilisateur doit être un [[doku>pagename|nom de page]] valide.
+Remplissez toutes les informations ci-dessous pour vous créer un compte sur ce wiki. Assurez-vous de fournir une **adresse de courriel valide** - s'il ne vous est pas demandé de saisir un mot de passe ici, il vous sera expédié par courriel à cette adresse. Le nom d'utilisateur doit être un [[doku>pagename|nom de page]] valide.
diff --git a/inc/lang/fr/registermail.txt b/inc/lang/fr/registermail.txt
index 1beae8522..43d72dba9 100644
--- a/inc/lang/fr/registermail.txt
+++ b/inc/lang/fr/registermail.txt
@@ -2,13 +2,13 @@ Un nouvel utilisateur s'est enregistré. Voici les détails :
Utilisateur : @NEWUSER@
Nom : @NEWNAME@
-Adresse de courriel : @NEWEMAIL@
+Courriel : @NEWEMAIL@
Date : @DATE@
-Navigateur : @BROWSER@
+Navigateur internet : @BROWSER@
Adresse IP : @IPADDRESS@
Nom d'hôte : @HOSTNAME@
--
-Ce courriel a été généré par DokuWiki
+Ce courriel a été généré par DokuWiki depuis
@DOKUWIKIURL@
diff --git a/inc/lang/fr/resendpwd.txt b/inc/lang/fr/resendpwd.txt
index 44fbeef03..91dd92482 100644
--- a/inc/lang/fr/resendpwd.txt
+++ b/inc/lang/fr/resendpwd.txt
@@ -1,4 +1,4 @@
====== Envoyer un nouveau mot de passe ======
-Veuillez compléter les champs ci-dessous pour obtenir un nouveau mot de passe pour votre compte dans ce wiki. Un lien de confirmation vous sera envoyé à l'adresse de courriel utilisée lors de votre enregistrement.
+Veuillez compléter les champs ci-dessous pour obtenir un nouveau mot de passe pour votre compte dans ce wiki. Un lien de confirmation vous sera expédié à l'adresse de courriel utilisée lors de votre enregistrement.
diff --git a/inc/lang/fr/stopwords.txt b/inc/lang/fr/stopwords.txt
index 981bae26b..5f187f7e1 100644
--- a/inc/lang/fr/stopwords.txt
+++ b/inc/lang/fr/stopwords.txt
@@ -1,5 +1,5 @@
-# Cette liste regroupe des mots ignorés par l'indexeur
-# Chaque ligne comporte un mot
+# Cette liste regroupe les mots ignorés par l'indexeur
+# Un seul mot par ligne
# Les fins de ligne de ce fichier doivent être de type UNIX
# Les mots de moins de 3 lettres sont ignorés par défaut.
# Cette liste est basée sur http://www.ranks.nl/stopwords/
diff --git a/inc/lang/fr/subscr_digest.txt b/inc/lang/fr/subscr_digest.txt
index 1803407fa..7ec75ca76 100644
--- a/inc/lang/fr/subscr_digest.txt
+++ b/inc/lang/fr/subscr_digest.txt
@@ -1,6 +1,6 @@
Bonjour,
-La page « @PAGE@ » dans le wiki « @TITLE@ » a été modifiée. Voici ces modifications :
+La page « @PAGE@ » dans le wiki « @TITLE@ » a été modifiée. Voici les modifications :
--------------------------------------------------------
@DIFF@
@@ -15,5 +15,5 @@ Pour annuler les notifications de page, connectez-vous au wiki à l'adresse
et désabonnez-vous de la page ou de la catégorie.
--
-Ce courriel a été généré par Dokuwiki :
+Ce courriel a été généré par DokuWiki depuis
@DOKUWIKIURL@ \ No newline at end of file
diff --git a/inc/lang/fr/subscr_form.txt b/inc/lang/fr/subscr_form.txt
index 528f77475..49c0cf443 100644
--- a/inc/lang/fr/subscr_form.txt
+++ b/inc/lang/fr/subscr_form.txt
@@ -1,3 +1,3 @@
====== Gestion de l'abonnement ======
-Cette page vous permet de gérer vos abonnements à la page ou à la catégorie courantes \ No newline at end of file
+Cette page vous permet de gérer vos abonnements à la page et à la catégorie courantes \ No newline at end of file
diff --git a/inc/lang/fr/subscr_list.txt b/inc/lang/fr/subscr_list.txt
index 3387b11ee..d8c6b68e4 100644
--- a/inc/lang/fr/subscr_list.txt
+++ b/inc/lang/fr/subscr_list.txt
@@ -1,6 +1,6 @@
Bonjour,
-Des pages dans la catégorie « @PAGE@ » du wiki « @TITLE@ » ont été modifiées. Voici ces modifications :
+Des pages de la catégorie « @PAGE@ » du wiki « @TITLE@ » ont été modifiées. Voici les modifications :
--------------------------------------------------------
@DIFF@
diff --git a/inc/lang/fr/subscr_single.txt b/inc/lang/fr/subscr_single.txt
index 1b9d5e1b5..236d45e8f 100644
--- a/inc/lang/fr/subscr_single.txt
+++ b/inc/lang/fr/subscr_single.txt
@@ -1,6 +1,6 @@
Bonjour,
-La page « @PAGE@ » dans le wiki « @TITLE@ » a été modifiée. Voici ces modifications :
+La page « @PAGE@ » dans le wiki « @TITLE@ » a été modifiée. Voici les modifications :
--------------------------------------------------------
@DIFF@
@@ -18,5 +18,5 @@ Pour annuler les notifications de page, connectez-vous au wiki à l'adresse
et désabonnez-vous de la page ou de la catégorie.
--
-Ce courriel a été généré par Dokuwiki :
+Ce courriel a été généré par Dokuwiki depuis
@DOKUWIKIURL@ \ No newline at end of file
diff --git a/inc/lang/fr/uploadmail.txt b/inc/lang/fr/uploadmail.txt
index 05b3205d7..80be0de8c 100644
--- a/inc/lang/fr/uploadmail.txt
+++ b/inc/lang/fr/uploadmail.txt
@@ -1,4 +1,4 @@
-Un fichier a été téléversé dans votre wiki. En voici les détails :
+Un fichier a été envoyé dans votre wiki. Voici les détails :
Fichier : @MEDIA@
Date : @DATE@
@@ -10,5 +10,5 @@ Type MIME : @MIME@
Utilisateur : @USER@
--
-Ce message a été généré par DokuWiki
+Ce message a été généré par DokuWiki depuis
@DOKUWIKIURL@
diff --git a/inc/lang/gl/lang.php b/inc/lang/gl/lang.php
index 23bd9a741..7cc06a833 100644
--- a/inc/lang/gl/lang.php
+++ b/inc/lang/gl/lang.php
@@ -5,6 +5,7 @@
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@gmail.com>
+ * @author Rodrigo Rega <rodrigorega@gmail.com>
*/
$lang['encoding'] = 'utf-8';
$lang['direction'] = 'ltr';
@@ -40,6 +41,7 @@ $lang['btn_backtomedia'] = 'Volver á Selección de Arquivos-Media';
$lang['btn_subscribe'] = 'Avísame dos trocos na páxina';
$lang['btn_profile'] = 'Actualizar Perfil';
$lang['btn_reset'] = 'Reiniciar';
+$lang['btn_resendpwd'] = 'Establecer novo contrasinal';
$lang['btn_draft'] = 'Editar borrador';
$lang['btn_recover'] = 'Recuperar borrador';
$lang['btn_draftdel'] = 'Eliminar borrador';
@@ -76,6 +78,7 @@ $lang['profnoempty'] = 'Non se permite un nome ou un enderezo de corre
$lang['profchanged'] = 'Perfil de usuario actualizado correctamente.';
$lang['pwdforget'] = 'Esqueceches o teu contrasinal? Consegue un novo';
$lang['resendna'] = 'Este wiki non permite o reenvío de contrasinais.';
+$lang['resendpwd'] = 'Establecer novo contrasinal para';
$lang['resendpwdmissing'] = 'Sentímolo, tes que cubrir todos os campos.';
$lang['resendpwdnouser'] = 'Sentímolo, non atopamos este usuario no noso banco de datos.';
$lang['resendpwdbadauth'] = 'Sentímolo, mais este código de autorización non é válido. Asegúrate de que usaches a ligazón completa de confirmación.';
@@ -88,6 +91,7 @@ $lang['searchmedia_in'] = 'Procurar en %s';
$lang['txt_upload'] = 'Escolle o arquivo para subir';
$lang['txt_filename'] = 'Subir como (opcional)';
$lang['txt_overwrt'] = 'Sobrescribir arquivo existente';
+$lang['maxuploadsize'] = 'Subida máxima %s por arquivo.';
$lang['lockedby'] = 'Bloqueado actualmente por';
$lang['lockexpire'] = 'O bloqueo remata o';
$lang['js']['willexpire'] = 'O teu bloqueo para editares esta páxina vai caducar nun minuto.\nPara de evitar conflitos, emprega o botón de previsualización para reiniciares o contador do tempo de bloqueo.';
@@ -182,6 +186,12 @@ $lang['external_edit'] = 'edición externa';
$lang['summary'] = 'Resumo da edición';
$lang['noflash'] = 'Precísase o <a href="http://www.adobe.com/products/flashplayer/">Extensión Adobe Flash</a> para amosar este contido.';
$lang['download'] = 'Descargar Retallo (Snippet)';
+$lang['tools'] = 'Ferramentas';
+$lang['user_tools'] = 'Ferramentas de usuario';
+$lang['site_tools'] = 'Ferramentas do sitio';
+$lang['page_tools'] = 'Ferramentas de páxina';
+$lang['skip_to_content'] = 'Pasar ao contido';
+$lang['sidebar'] = 'Barra lateral';
$lang['mail_newpage'] = 'páxina engadida:';
$lang['mail_changed'] = 'páxina mudada:';
$lang['mail_subscribe_list'] = 'páxinas mudadas en nome de espazo:';
@@ -252,6 +262,7 @@ $lang['subscr_style_digest'] = 'correo-e con resumo de trocos para cada páxin
$lang['subscr_style_list'] = 'lista de páxinas mudadas dende o último correo-e';
$lang['authmodfailed'] = 'Configuración de autenticación de usuario incorrecta. Por favor, informa ao Administrador do teu Wiki.';
$lang['authtempfail'] = 'A autenticación de usuario non está dispoñible de xeito temporal. De persistir esta situación, por favor, informa ao Administrador do teu Wiki.';
+$lang['authpwdexpire'] = 'A túa contrasinal expirará en %d días, deberías cambiala pronto.';
$lang['i_chooselang'] = 'Escolle o teu idioma';
$lang['i_installer'] = 'Instalador do DokuWiki';
$lang['i_wikiname'] = 'Nome do Wiki';
diff --git a/inc/lang/gl/mailwrap.html b/inc/lang/gl/mailwrap.html
new file mode 100644
index 000000000..19927c117
--- /dev/null
+++ b/inc/lang/gl/mailwrap.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>@TITLE@</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+
+@HTMLBODY@
+
+<br /><hr />
+<small>Este correo era xerado por DokuWiki en @DOKUWIKIURL@.</small>
+</body>
+</html> \ No newline at end of file
diff --git a/inc/lang/gl/resetpwd.txt b/inc/lang/gl/resetpwd.txt
new file mode 100644
index 000000000..d3d64e90d
--- /dev/null
+++ b/inc/lang/gl/resetpwd.txt
@@ -0,0 +1,3 @@
+====== Establecer novo contrasinal ======
+
+Por favor introduzca un novo contrasinal para a súa conta neste wiki. \ No newline at end of file
diff --git a/inc/lang/he/lang.php b/inc/lang/he/lang.php
index 00eb4549b..e474501ae 100644
--- a/inc/lang/he/lang.php
+++ b/inc/lang/he/lang.php
@@ -249,8 +249,8 @@ $lang['i_confexists'] = '<code>%s</code> כבר קיים';
$lang['i_writeerr'] = 'אין אפשרות ליצור את <code>%s</code>. נא לבדוק את הרשאות הקובץ/תיקייה וליצור את הקובץ ידנית.';
$lang['i_badhash'] = 'הקובץ Dokuwiki.php אינו מזוהה או שעבר שינויים (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - הערך אינו חוקי או ריק';
-$lang['i_success'] = 'תהליך ההגדרה הסתיים בהצלחה. כעת ניתן למחוק את הקובץ install.php ולהמשיך אל ה־<a href="doku.php">DokuWiki החדש שלך</a>.';
-$lang['i_failure'] = 'מספר שגיאות אירעו בעת כתיבת קובצי התצורה. יתכן כי יהיה צורך לתקנם ידנית לפני שניתן יהיה להשתמש ב־<a href="doku.php">DokuWiki החדש שלך</a>.';
+$lang['i_success'] = 'תהליך ההגדרה הסתיים בהצלחה. כעת ניתן למחוק את הקובץ install.php ולהמשיך אל ה־<a href="doku.php?id=wiki:welcome">DokuWiki החדש שלך</a>.';
+$lang['i_failure'] = 'מספר שגיאות אירעו בעת כתיבת קובצי התצורה. יתכן כי יהיה צורך לתקנם ידנית לפני שניתן יהיה להשתמש ב־<a href="doku.php?id=wiki:welcome">DokuWiki החדש שלך</a>.';
$lang['i_policy'] = 'מדיניות ACL התחלתית';
$lang['i_pol0'] = 'ויקי פתוח (קריאה, כתיבה והעלאה לכולם)';
$lang['i_pol1'] = ' ויקי ציבורי (קריאה לכולם, כתיבה והעלאה למשתמשים רשומים)';
diff --git a/inc/lang/he/subscr_single.txt b/inc/lang/he/subscr_single.txt
index 123b186c8..78b551e2f 100644
--- a/inc/lang/he/subscr_single.txt
+++ b/inc/lang/he/subscr_single.txt
@@ -14,7 +14,7 @@
לביטול התרעות בנוגע לעמוד, יש להיכנס לאתר הוויקי בכתובת
@DOKUWIKIURL@ ואז לבקר בדף
-@NEWPAGE@
+@SUBSCRIBE@
ולבטל את המינוי לקבלת שינויים בדף ו/או במרחב השם.
--
diff --git a/inc/lang/hr/lang.php b/inc/lang/hr/lang.php
index a0438d915..97f4cf0c2 100644
--- a/inc/lang/hr/lang.php
+++ b/inc/lang/hr/lang.php
@@ -247,8 +247,8 @@ $lang['i_confexists'] = '<code>%s</code> već postoji';
$lang['i_writeerr'] = 'Ne može se kreirati <code>%s</code>. Trebate provjeriti dozvole direktorija/datoteke i kreirati dokument ručno.';
$lang['i_badhash'] = 'neprepoznat ili promijenjen dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - nedozvoljena ili prazna vrijednost';
-$lang['i_success'] = 'Konfiguracija je uspješno završena. Sada možete obrisati install.php datoteku. Nastavite na <a href="doku.php">vaš novi DokuWiki</a>.';
-$lang['i_failure'] = 'Pojavile su se neke greške prilikom pisanja konfiguracijskih datoteka. Morati ćete ih ručno ispraviti da bi mogli koristiti <a href="doku.php">vaš novi DokuWiki</a>.';
+$lang['i_success'] = 'Konfiguracija je uspješno završena. Sada možete obrisati install.php datoteku. Nastavite na <a href="doku.php?id=wiki:welcome">vaš novi DokuWiki</a>.';
+$lang['i_failure'] = 'Pojavile su se neke greške prilikom pisanja konfiguracijskih datoteka. Morati ćete ih ručno ispraviti da bi mogli koristiti <a href="doku.php?id=wiki:welcome">vaš novi DokuWiki</a>.';
$lang['i_policy'] = 'Inicijalna ACL politika';
$lang['i_pol0'] = 'Otvoreni Wiki (čitanje, pisanje, učitavanje za sve)';
$lang['i_pol1'] = 'Javni Wiki (čitanje za sve, pisanje i učitavanje za registrirane korisnike)';
diff --git a/inc/lang/hu/lang.php b/inc/lang/hu/lang.php
index 671b225f2..c59cace77 100644
--- a/inc/lang/hu/lang.php
+++ b/inc/lang/hu/lang.php
@@ -252,8 +252,8 @@ $lang['i_confexists'] = '<code>%s</code> már létezik.';
$lang['i_writeerr'] = 'Nem tudom ezt létrehozni: <code>%s</code>. Ellenőrizd a könyvtár/fájl jogosultságokat, és hozd létre az állományt kézzel.';
$lang['i_badhash'] = 'A dokuwiki.php nem felismerhető vagy módosított (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - 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 <a href="doku.php">új DokuWikidet</a>!';
-$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 <a href="doku.php">új DokuWikidet</a>.';
+$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 <a href="doku.php?id=wiki:welcome">új DokuWikidet</a>!';
+$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 <a href="doku.php?id=wiki:welcome">új DokuWikidet</a>.';
$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)';
diff --git a/inc/lang/ia/lang.php b/inc/lang/ia/lang.php
index d7be1eff3..a9d5c376c 100644
--- a/inc/lang/ia/lang.php
+++ b/inc/lang/ia/lang.php
@@ -247,9 +247,9 @@ $lang['i_writeerr'] = 'Impossibile crear <code>%s</code>. Tu debe ver
$lang['i_badhash'] = 'dokuwiki.php non recognoscite o modificate (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - valor vacue o invalide';
$lang['i_success'] = 'Le configuration ha succedite. Tu pote ora deler le file install.php. Continua a
-<a href="doku.php">tu nove DokuWiki</a>.';
+<a href="doku.php?id=wiki:welcome">tu nove DokuWiki</a>.';
$lang['i_failure'] = 'Alcun errores occurreva durante le scriptura del files de configuration. Es possibile que tu debe remediar iste errores manualmente ante que
-tu pote usar <a href="doku.php">tu nove DokuWiki</a>.';
+tu pote usar <a href="doku.php?id=wiki:welcome">tu nove DokuWiki</a>.';
$lang['i_policy'] = 'Politica de ACL interne';
$lang['i_pol0'] = 'Wiki aperte (lectura, scriptura, incargamento pro omnes)';
$lang['i_pol1'] = 'Wiki public (lectura pro omnes, scriptura e incargamento pro usatores registrate)';
diff --git a/inc/lang/ia/subscr_single.txt b/inc/lang/ia/subscr_single.txt
index 3d6ef7103..445df197c 100644
--- a/inc/lang/ia/subscr_single.txt
+++ b/inc/lang/ia/subscr_single.txt
@@ -15,7 +15,7 @@ Version nove: @NEWPAGE@
Pro cancellar le notificationes de paginas, aperi un session al wiki a
@DOKUWIKIURL@ postea visita
-@NEWPAGE@
+@SUBSCRIBE@
e cancella tu subscription al modificationes in paginas e/o spatios de nomines.
--
diff --git a/inc/lang/id/lang.php b/inc/lang/id/lang.php
index 2302d4f6f..91ed38e31 100644
--- a/inc/lang/id/lang.php
+++ b/inc/lang/id/lang.php
@@ -188,8 +188,8 @@ $lang['i_confexists'] = '<code>%s</code> sudah ada';
$lang['i_writeerr'] = 'Tidak dapat membuat <code>%s</code>. Anda harus memeriksa konfigurasi hak akses direktori/berkas dan membuatnya secara manual.';
$lang['i_badhash'] = 'dokuwiki.php tidak dikenal atau sudah diubah (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - tidak valid atau belum diisi';
-$lang['i_success'] = 'Konfigurasi telah berhasil. Anda boleh menghapus berkas install.php sekarang. Lanjutkan ke <a href="doku.php">DokuWiki baru Anda</a>.';
-$lang['i_failure'] = 'Terdapat beberapa kesalahan dalam menulis berkas konfigurasi. Anda harus memperbaikinnya sendiri sebelum dapat menggunakan <a href="doku.php">DokuWiki baru Anda</a>.';
+$lang['i_success'] = 'Konfigurasi telah berhasil. Anda boleh menghapus berkas install.php sekarang. Lanjutkan ke <a href="doku.php?id=wiki:welcome">DokuWiki baru Anda</a>.';
+$lang['i_failure'] = 'Terdapat beberapa kesalahan dalam menulis berkas konfigurasi. Anda harus memperbaikinnya sendiri sebelum dapat menggunakan <a href="doku.php?id=wiki:welcome">DokuWiki baru Anda</a>.';
$lang['i_policy'] = 'Policy ACL awal';
$lang['i_pol0'] = 'Wiki Terbuka (baca, tulis, upload untuk semua orang)';
$lang['i_pol1'] = 'Wiki Publik (baca untuk semua orang, tulis dan upload untuk pengguna terdaftar)';
diff --git a/inc/lang/it/lang.php b/inc/lang/it/lang.php
index a415f2a2c..1ad5ae1bb 100644
--- a/inc/lang/it/lang.php
+++ b/inc/lang/it/lang.php
@@ -284,8 +284,8 @@ $lang['i_confexists'] = '<code>%s</code> esiste già';
$lang['i_writeerr'] = 'Impossibile creare <code>%s</code>. E\' necessario verificare i permessi della directory o del file oppure creare il file manualmente.';
$lang['i_badhash'] = 'dokuwiki.php (hash=<code>%s</code>) non riconosciuto o modificato';
$lang['i_badval'] = '<code>%s</code> - valore vuoto o non valido';
-$lang['i_success'] = 'La configurazione è stata completata correttamente. Ora è possibile eliminare il file install.php. Poi, visita <a href="doku.php">il tuo nuovo DokuWiki</a>.';
-$lang['i_failure'] = 'Si sono verificati errori durante la scrittura dei file di configurazione. Potrebbe essere necessario correggerli manualmente prima di poter utilizzare <a href="doku.php">il tuo nuovo DokuWiki</a>.';
+$lang['i_success'] = 'La configurazione è stata completata correttamente. Ora è possibile eliminare il file install.php. Poi, visita <a href="doku.php?id=wiki:welcome">il tuo nuovo DokuWiki</a>.';
+$lang['i_failure'] = 'Si sono verificati errori durante la scrittura dei file di configurazione. Potrebbe essere necessario correggerli manualmente prima di poter utilizzare <a href="doku.php?id=wiki:welcome">il tuo nuovo DokuWiki</a>.';
$lang['i_policy'] = 'Regole di accesso iniziali';
$lang['i_pol0'] = 'Wiki Aperto (lettura, scrittura, caricamento file per tutti)';
$lang['i_pol1'] = 'Wiki Pubblico (lettura per tutti, scrittura e caricamento file per gli utenti registrati)';
diff --git a/inc/lang/it/subscr_single.txt b/inc/lang/it/subscr_single.txt
index 8cde8ea0f..a8649a4ef 100644
--- a/inc/lang/it/subscr_single.txt
+++ b/inc/lang/it/subscr_single.txt
@@ -15,7 +15,7 @@ Nuova revisione: @NEWPAGE@
Per non ricevere più queste notifiche, collegati al
wiki all'indirizzo @DOKUWIKIURL@ e poi visita
-@NEWPAGE@
+@SUBSCRIBE@
e rimuovi la sottoscrizione alle modifiche della
pagina o categoria.
diff --git a/inc/lang/ja/lang.php b/inc/lang/ja/lang.php
index 791ef9a6e..66de0dab5 100644
--- a/inc/lang/ja/lang.php
+++ b/inc/lang/ja/lang.php
@@ -278,8 +278,8 @@ $lang['i_confexists'] = '<code>%s</code> は既に存在します';
$lang['i_writeerr'] = '<code>%s</code> を作成できません。ディレクトリとファイルの権限を確認し、それらを手動で作成する必要があります。';
$lang['i_badhash'] = 'dokuwiki.php が認識できないか、編集されています(hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - 正しくない、もしくは値が空です';
-$lang['i_success'] = '設定ファイルは正しく作成されました。<a href="doku.php">作成した DokuWiki</a>を使用するには install.php を削除してください。';
-$lang['i_failure'] = '設定ファイルの作成中にエラーが発生しました。<a href="doku.php">作成した DokuWiki</a>を使用する前に、それらの問題を手動で修正する必要があります。';
+$lang['i_success'] = '設定ファイルは正しく作成されました。<a href="doku.php?id=wiki:welcome">作成した DokuWiki</a>を使用するには install.php を削除してください。';
+$lang['i_failure'] = '設定ファイルの作成中にエラーが発生しました。<a href="doku.php?id=wiki:welcome">作成した DokuWiki</a>を使用する前に、それらの問題を手動で修正する必要があります。';
$lang['i_policy'] = 'ACL初期設定';
$lang['i_pol0'] = 'オープン Wiki(全ての人に、閲覧・書き込み・アップロードを許可)';
$lang['i_pol1'] = 'パブリック Wiki(閲覧は全ての人が可能、書き込み・アップロードは登録ユーザーのみ)';
diff --git a/inc/lang/ko/lang.php b/inc/lang/ko/lang.php
index 89d045503..e5b21aef8 100644
--- a/inc/lang/ko/lang.php
+++ b/inc/lang/ko/lang.php
@@ -280,8 +280,8 @@ $lang['i_confexists'] = '<code>%s</code>(은)는 이미 존재합니다
$lang['i_writeerr'] = '<code>%s</code>(을)를 만들 수 없습니다. 먼저 디렉토리/파일 권한을 확인하고 파일을 수동으로 만들기 바랍니다.';
$lang['i_badhash'] = 'dokuwiki.php를 인식할 수 없거나 원본 파일이 아닙니다. (해시=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - 유효하지 않거나 빈 값입니다.';
-$lang['i_success'] = '환경 설정이 성공적으로 끝났습니다. 지금 install.php를 지워도 상관없습니다. <a href="doku.php">새 DokuWiki</a>로 들어갑니다.';
-$lang['i_failure'] = '환경 설정 파일에 쓰는 도중에 오류가 발생했습니다. <a href="doku.php">새 DokuWiki</a>를 사용하기 전에 수동으로 문제를 해결할 필요가 있습니다.';
+$lang['i_success'] = '환경 설정이 성공적으로 끝났습니다. 지금 install.php를 지워도 상관없습니다. <a href="doku.php?id=wiki:welcome">새 DokuWiki</a>로 들어갑니다.';
+$lang['i_failure'] = '환경 설정 파일에 쓰는 도중에 오류가 발생했습니다. <a href="doku.php?id=wiki:welcome">새 DokuWiki</a>를 사용하기 전에 수동으로 문제를 해결할 필요가 있습니다.';
$lang['i_policy'] = '초기 ACL 정책';
$lang['i_pol0'] = '열린 위키 (누구나 읽기, 쓰기, 올리기가 가능합니다.)';
$lang['i_pol1'] = '공개 위키 (누구나 읽을 수 있지만, 등록된 사용자만 쓰기와 올리기가 가능합니다.)';
diff --git a/inc/lang/ko/subscr_single.txt b/inc/lang/ko/subscr_single.txt
index 6bd1885e6..2679db393 100644
--- a/inc/lang/ko/subscr_single.txt
+++ b/inc/lang/ko/subscr_single.txt
@@ -14,7 +14,7 @@
새 버전 : @NEWPAGE@
이 문서의 알림을 취소하려면, @DOKUWIKIURL@에 로그인한 뒤
-@NEWPAGE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요.
+@SUBSCRIBE@ 문서를 방문하여 문서나 이름공간의 구독을 취소하세요.
--
@DOKUWIKIURL@의 DokuWiki가 자동으로 만들어낸 메일입니다. \ No newline at end of file
diff --git a/inc/lang/la/lang.php b/inc/lang/la/lang.php
index 3970f453a..77fec8362 100644
--- a/inc/lang/la/lang.php
+++ b/inc/lang/la/lang.php
@@ -246,8 +246,8 @@ $lang['i_confexists'] = '<code>%s</code> iam est.';
$lang['i_writeerr'] = '<code>%s</code> non creari potest. Manu illum creas.';
$lang['i_badhash'] = 'Ignotum uel mutatum dokuwiki.php (<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> non legitimum uel uacuom';
-$lang['i_success'] = 'Administratio feliciter perficitur. Delere install.php documentum potes. I ad <a href="doku.php">hanc paginam</a> ut continues.';
-$lang['i_failure'] = 'Aliqui errores dum documenta administrantur sunt. Manu onerare omnes potes priusquam <a href="doku.php">tuo nouo uice</a> uteris.';
+$lang['i_success'] = 'Administratio feliciter perficitur. Delere install.php documentum potes. I ad <a href="doku.php?id=wiki:welcome">hanc paginam</a> ut continues.';
+$lang['i_failure'] = 'Aliqui errores dum documenta administrantur sunt. Manu onerare omnes potes priusquam <a href="doku.php?id=wiki:welcome">tuo nouo uice</a> uteris.';
$lang['i_policy'] = 'ICA ratio prima';
$lang['i_pol0'] = 'Vicem aperire (omnes legere, scribere, onerare possunt)';
$lang['i_pol1'] = 'Publicus uicis (omnes legere, Sodales scribere et onerare possunt)';
diff --git a/inc/lang/la/subscr_digest.txt b/inc/lang/la/subscr_digest.txt
index 629213359..32d378a7e 100644
--- a/inc/lang/la/subscr_digest.txt
+++ b/inc/lang/la/subscr_digest.txt
@@ -12,7 +12,7 @@ Noua recensio: @NEWPAGE@
Ut paginae adnotationes deleas, in uicem ineas in
@DOKUWIKIURL@, deinde uideas
-@NEWPAGE@
+@SUBSCRIBE@
et paginarum generum optiones mutes.
--
diff --git a/inc/lang/la/subscr_single.txt b/inc/lang/la/subscr_single.txt
index 7839791ea..14285014c 100644
--- a/inc/lang/la/subscr_single.txt
+++ b/inc/lang/la/subscr_single.txt
@@ -15,7 +15,7 @@ Noua recensio: @NEWPAGE@
Ut paginae adnotationes deleas, in uicem ineas in
@DOKUWIKIURL@, deinde uideas
-@NEWPAGE@
+@SUBSCRIBE@
et paginarum et\aut generum optiones mutasa.
--
diff --git a/inc/lang/lv/lang.php b/inc/lang/lv/lang.php
index 19a7b7cce..671e5f52a 100644
--- a/inc/lang/lv/lang.php
+++ b/inc/lang/lv/lang.php
@@ -275,8 +275,8 @@ $lang['i_confexists'] = '<code>%s</code> jau ir';
$lang['i_writeerr'] = 'Nevar izveidot <code>%s</code>. Jāpārbauda direktorijas/faila tiesības un fails jāizveido pašam.';
$lang['i_badhash'] = 'nepazīstams vai izmainīts dokuwiki.php fails (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - neatļauta vai tukša vērtība';
-$lang['i_success'] = 'Konfigurēšana veiksmīgi pabeigta. Tagad vari nodzēst failu install.php. Tālāk turpini <a href="doku.php">savā jaunajā DokuWiki</a>.';
-$lang['i_failure'] = 'Rakstot konfigurācijas failu, gadījās dažas kļūmes. Pirms lieto <a href="doku.php">savu jauno DokuWiki</a>, tās varbūt jāizlabo.';
+$lang['i_success'] = 'Konfigurēšana veiksmīgi pabeigta. Tagad vari nodzēst failu install.php. Tālāk turpini <a href="doku.php?id=wiki:welcome">savā jaunajā DokuWiki</a>.';
+$lang['i_failure'] = 'Rakstot konfigurācijas failu, gadījās dažas kļūmes. Pirms lieto <a href="doku.php?id=wiki:welcome">savu jauno DokuWiki</a>, tās varbūt jāizlabo.';
$lang['i_policy'] = 'Sākotnējā ACL politika';
$lang['i_pol0'] = 'Atvērts Wiki (raksta, lasa un augšupielādē ikviens)';
$lang['i_pol1'] = 'Publisks Wiki (lasa ikviens, raksta un augšupielādē reģistrēti lietotāji)';
diff --git a/inc/lang/mk/lang.php b/inc/lang/mk/lang.php
index 62400063c..7482f2512 100644
--- a/inc/lang/mk/lang.php
+++ b/inc/lang/mk/lang.php
@@ -214,8 +214,8 @@ $lang['i_confexists'] = '<code>%s</code> веќе постои';
$lang['i_writeerr'] = 'Не може да се креира <code>%s</code>. Треба да ги проверите пермисиите на директориумот/датотеката и рачно да ја креирате датотеката.';
$lang['i_badhash'] = 'непозната или изменете dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - нелегална или празна вредност';
-$lang['i_success'] = 'Конфигурацијата успешно заврши. Сега можете да ја избришете датотеката install.php. Продолжете до <a href="doku.php">вашето ново DokuWiki</a>.';
-$lang['i_failure'] = 'Се појавија некои грешки при запишувањето на конфигурациските датотеки. Можеби треба да ги поравите рачно пред да можете да го користите <a href="doku.php">вашето ново DokuWiki</a>.';
+$lang['i_success'] = 'Конфигурацијата успешно заврши. Сега можете да ја избришете датотеката install.php. Продолжете до <a href="doku.php?id=wiki:welcome">вашето ново DokuWiki</a>.';
+$lang['i_failure'] = 'Се појавија некои грешки при запишувањето на конфигурациските датотеки. Можеби треба да ги поравите рачно пред да можете да го користите <a href="doku.php?id=wiki:welcome">вашето ново DokuWiki</a>.';
$lang['i_policy'] = 'Почетна ACL политика';
$lang['i_pol0'] = 'Отвори вики (читај, запиши, качи за сите)';
$lang['i_pol1'] = 'Јавно вики (читај за сите, запиши и качи за регистрирани корисници)';
diff --git a/inc/lang/mr/lang.php b/inc/lang/mr/lang.php
index 32781e6d4..b754a3f1c 100644
--- a/inc/lang/mr/lang.php
+++ b/inc/lang/mr/lang.php
@@ -258,8 +258,8 @@ $lang['i_confexists'] = '<code>%s</code> आधीच अस्ति
$lang['i_writeerr'] = '<code>%s</code> निर्माण करू शकलो नाही. तुम्हाला डिरेक्टरी / फाइल च्या परवानग्या तपासून स्वतःच ही फाइल बनवावी लागेल.';
$lang['i_badhash'] = 'अनाकलनीय किंवा बदललेले dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = 'code>%s</code> - अवैध किंवा रिकामा मजकूर.';
-$lang['i_success'] = 'व्यवस्था लावण्याचे काम यशस्वीरीत्या पार पडले. आता तुम्ही install.php डिलीट करू शकता. <a href="doku.php">तुमच्या नविन डॉक्युविकि </a> वर जा.';
-$lang['i_failure'] = 'कॉन्फिगुरेशनच्या फाइल सुरक्षित करताना काही अडचणी आल्या आहेत. <a href="doku.php">तुमची नवीन डॉक्युविकि </a> वापरण्याआधी तुम्हाला ह्या फाइल स्वतः ठीक कराव्या लागतील.';
+$lang['i_success'] = 'व्यवस्था लावण्याचे काम यशस्वीरीत्या पार पडले. आता तुम्ही install.php डिलीट करू शकता. <a href="doku.php?id=wiki:welcome">तुमच्या नविन डॉक्युविकि </a> वर जा.';
+$lang['i_failure'] = 'कॉन्फिगुरेशनच्या फाइल सुरक्षित करताना काही अडचणी आल्या आहेत. <a href="doku.php?id=wiki:welcome">तुमची नवीन डॉक्युविकि </a> वापरण्याआधी तुम्हाला ह्या फाइल स्वतः ठीक कराव्या लागतील.';
$lang['i_policy'] = 'आरंभीची ACL पॉलिसी';
$lang['i_pol0'] = 'मुक्त विकी ( सर्वांना वाचन, लेखन व अपलोड करण्याची परवानगी )';
$lang['i_pol1'] = 'सार्वजनिक विकी ( सर्वांना वाचण्याची मुभा , लेखन व अपलोडची परवानगी फक्त नोंदणीकृत सदस्यांना )';
diff --git a/inc/lang/ne/lang.php b/inc/lang/ne/lang.php
index 82ca389f7..fa6d2f705 100644
--- a/inc/lang/ne/lang.php
+++ b/inc/lang/ne/lang.php
@@ -191,8 +191,8 @@ $lang['i_confexists'] = '<code>%s</code> पहिले देखि
$lang['i_writeerr'] = '<code>%s</code> बनाउन असमर्थ । तपाईले डाइरेक्टरी / फाइल अनुमति जाच्नु पर्छ र फाइल आफैले बनाउनु पर्छ ।';
$lang['i_badhash'] = 'पहिचान हुन नसकेको वा परिवर्तित okuwiki.php (hash=code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - अवैध वा रित्तो मान ';
-$lang['i_success'] = 'स्थापना सफलरुपमा समाप्त भयो ।तपाई install.php मेट्न सक्नुहु्न्छ । <a href="doku.php">तपाईको नयाँ DokuWiki</a> निरन्तर गर्न सक्नुहुन्छ ।';
-$lang['i_failure'] = 'स्थापना समयमा केहि त्रुटि फेला पर्यो ।तपाईले आफैले यसलाई <a href="doku.php">तपाईको नयाँ DokuWiki</a> प्रयोग गर्नु अगि सच्याउनुपर्ने हुन्छ ।';
+$lang['i_success'] = 'स्थापना सफलरुपमा समाप्त भयो ।तपाई install.php मेट्न सक्नुहु्न्छ । <a href="doku.php?id=wiki:welcome">तपाईको नयाँ DokuWiki</a> निरन्तर गर्न सक्नुहुन्छ ।';
+$lang['i_failure'] = 'स्थापना समयमा केहि त्रुटि फेला पर्यो ।तपाईले आफैले यसलाई <a href="doku.php?id=wiki:welcome">तपाईको नयाँ DokuWiki</a> प्रयोग गर्नु अगि सच्याउनुपर्ने हुन्छ ।';
$lang['i_policy'] = 'सुरुको ACL निति';
$lang['i_pol0'] = 'खुल्ला विकि (पठन, लेखन , अपलोड ) सबैका लागि';
$lang['i_pol1'] = 'Public विकि (पठन सवैका लागि,लेखन र अपलोड दर्ता गरिएका प्रयपगकर्ताका लागि ) ';
diff --git a/inc/lang/nl/lang.php b/inc/lang/nl/lang.php
index fdc0c075a..0241eab2f 100644
--- a/inc/lang/nl/lang.php
+++ b/inc/lang/nl/lang.php
@@ -288,8 +288,8 @@ $lang['i_confexists'] = '<code>%s</code> bestaat reeds';
$lang['i_writeerr'] = 'Niet mogelijk om <code>%s</code> aan te maken. Controleer de directory/bestandspermissies en maak het bestand handmatig aan.';
$lang['i_badhash'] = 'Onbekende of aangepaste dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - onjuiste of lege waarde';
-$lang['i_success'] = 'De configuratie is succesvol afgerond. Je kunt nu het bestand install.php verwijderen. Ga naar <a href="doku.php">je nieuwe DokuWiki</a>.';
-$lang['i_failure'] = 'Fouten deden zich voor tijdens het schrijven naar de configuratiebestanden. Pas deze aan voor je gebruik kunt maken van <a href="doku.php">je nieuwe DokuWiki</a>.';
+$lang['i_success'] = 'De configuratie is succesvol afgerond. Je kunt nu het bestand install.php verwijderen. Ga naar <a href="doku.php?id=wiki:welcome">je nieuwe DokuWiki</a>.';
+$lang['i_failure'] = 'Fouten deden zich voor tijdens het schrijven naar de configuratiebestanden. Pas deze aan voor je gebruik kunt maken van <a href="doku.php?id=wiki:welcome">je nieuwe DokuWiki</a>.';
$lang['i_policy'] = 'Initieel ACL-beleid';
$lang['i_pol0'] = 'Open wiki (lezen, schrijven, uploaden voor iedereen)';
$lang['i_pol1'] = 'Publieke wiki (lezen voor iedereen, schrijven en uploaden voor geregistreerde gebruikers)';
diff --git a/inc/lang/no/lang.php b/inc/lang/no/lang.php
index cc3d34aed..9aa11ac87 100644
--- a/inc/lang/no/lang.php
+++ b/inc/lang/no/lang.php
@@ -282,9 +282,9 @@ $lang['i_writeerr'] = 'Kunne ikke opprette <code>%s</code>. Du må sj
$lang['i_badhash'] = 'ikke gjenkjent eller modifisert dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - ugyldig eller tom verdi';
$lang['i_success'] = 'Konfigurasjonen ble vellykket fullført. Du kan slette install.php filen nå. Fortsett til
- <a href="doku.php">din nye DokuWiki</a>.';
+ <a href="doku.php?id=wiki:welcome">din nye DokuWiki</a>.';
$lang['i_failure'] = 'En eller flere feil oppstod ved skriving til konfigurasjonsfilene. Du må kanskje fikse dem manuelt før
- du kan bruke <a href="doku.php">din nye DokuWiki</a>.';
+ du kan bruke <a href="doku.php?id=wiki:welcome">din nye DokuWiki</a>.';
$lang['i_policy'] = 'Innledende ACL-politikk';
$lang['i_pol0'] = 'Åpen Wiki (les, skriv og opplasting for alle)';
$lang['i_pol1'] = 'Offentlig Wiki (les for alle, skriving og opplasting bare for registrerte brukere)';
diff --git a/inc/lang/no/subscr_digest.txt b/inc/lang/no/subscr_digest.txt
index 6afd0cc5c..670d39d32 100644
--- a/inc/lang/no/subscr_digest.txt
+++ b/inc/lang/no/subscr_digest.txt
@@ -12,7 +12,7 @@ Ny versjon: @NEWPAGE@
For å avslutte varslingen, logg inn på
@DOKUWIKIURL@ og gå til
-@NEWPAGE@
+@SUBSCRIBE@
og avslutt abonnementet på endringer av siden eller i navnerommet.
--
diff --git a/inc/lang/no/subscr_list.txt b/inc/lang/no/subscr_list.txt
index 72cd307cb..860d88d2a 100644
--- a/inc/lang/no/subscr_list.txt
+++ b/inc/lang/no/subscr_list.txt
@@ -9,7 +9,7 @@ Her er endringene:
For å avslutte varslinga, logg inn på
@DOKUWIKIURL@ og gå til
-@NEWPAGE@
+@SUBSCRIBE@
og avslutt abonnementet på endringer av sida eller i navnerommet.
--
diff --git a/inc/lang/no/subscr_single.txt b/inc/lang/no/subscr_single.txt
index 25296da58..b26b3a879 100644
--- a/inc/lang/no/subscr_single.txt
+++ b/inc/lang/no/subscr_single.txt
@@ -15,7 +15,7 @@ Ny versjon: @NEWPAGE@
For å avslutte varslingen, logg inn på
@DOKUWIKIURL@, gå til
-@NEWPAGE@
+@SUBSCRIBE@
og avslutt abonnementet på endringer av siden eller i navnerommet.
--
diff --git a/inc/lang/pl/lang.php b/inc/lang/pl/lang.php
index 2f448d291..cf9fc6a16 100644
--- a/inc/lang/pl/lang.php
+++ b/inc/lang/pl/lang.php
@@ -285,8 +285,8 @@ $lang['i_confexists'] = '<code>%s</code> już istnieje';
$lang['i_writeerr'] = 'Nie można utworzyć <code>%s</code>. Sprawdź uprawnienia do katalogu lub pliku i stwórz plik ręcznie.';
$lang['i_badhash'] = 'nierozpoznany lub zmodyfikowany plik dokuwiki.php (skrót=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - nieprawidłowa wartość lub jej brak';
-$lang['i_success'] = 'Konfiguracja pomyślnie zakończona. Możesz teraz usunąć plik install.php. Przejdź do <a href="doku.php">Twojego nowego DokuWiki</a>.';
-$lang['i_failure'] = 'Podczas zapisu plików konfiguracyjnych wystąpiły błędy. Musisz usunąć wszystkie problemy, zanim zaczniesz korzystać z <a href="doku.php">Twojego nowego DokuWiki</a>.';
+$lang['i_success'] = 'Konfiguracja pomyślnie zakończona. Możesz teraz usunąć plik install.php. Przejdź do <a href="doku.php?id=wiki:welcome">Twojego nowego DokuWiki</a>.';
+$lang['i_failure'] = 'Podczas zapisu plików konfiguracyjnych wystąpiły błędy. Musisz usunąć wszystkie problemy, zanim zaczniesz korzystać z <a href="doku.php?id=wiki:welcome">Twojego nowego DokuWiki</a>.';
$lang['i_policy'] = 'Wstępna polityka uprawnień ACL';
$lang['i_pol0'] = 'Otwarte Wiki (odczyt, zapis i dodawanie plików dla wszystkich)';
$lang['i_pol1'] = 'Publiczne Wiki (odczyt dla wszystkich, zapis i dodawanie plików tylko dla zarejestrowanych użytkowników)';
diff --git a/inc/lang/pt-br/lang.php b/inc/lang/pt-br/lang.php
index b3d56bae7..992fae48a 100644
--- a/inc/lang/pt-br/lang.php
+++ b/inc/lang/pt-br/lang.php
@@ -291,8 +291,8 @@ $lang['i_confexists'] = '<code>%s</code> já existe';
$lang['i_writeerr'] = 'Não foi possível criar <code>%s</code>. É necessário checar as permissões de arquivos/diretórios e criar o arquivo manualmente.';
$lang['i_badhash'] = 'dokuwiki.php não reconhecido ou modificado (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - valor ilegal ou em branco';
-$lang['i_success'] = 'A configuração terminou com sucesso. Agora você deve excluir o arquivo install.php. Conheça o seu <a href="doku.php">novo DokuWiki</a>!';
-$lang['i_failure'] = 'Ocorreram alguns erros durante a escrita dos arquivos de configuração. É necessário corrigi-los manualmente antes de usar seu <a href="doku.php">novo DokuWiki</a>';
+$lang['i_success'] = 'A configuração terminou com sucesso. Agora você deve excluir o arquivo install.php. Conheça o seu <a href="doku.php?id=wiki:welcome">novo DokuWiki</a>!';
+$lang['i_failure'] = 'Ocorreram alguns erros durante a escrita dos arquivos de configuração. É necessário corrigi-los manualmente antes de usar seu <a href="doku.php?id=wiki:welcome">novo DokuWiki</a>';
$lang['i_policy'] = 'Política inicial de permissões';
$lang['i_pol0'] = 'Wiki aberto (leitura, escrita e envio de arquivos por todos)';
$lang['i_pol1'] = 'Wiki público (leitura por todos, escrita e envio de arquivos por usuários registrados)';
diff --git a/inc/lang/pt/lang.php b/inc/lang/pt/lang.php
index af388985c..1555889f6 100644
--- a/inc/lang/pt/lang.php
+++ b/inc/lang/pt/lang.php
@@ -268,8 +268,8 @@ $lang['i_confexists'] = '<code>%s</code> já existe';
$lang['i_writeerr'] = 'Não foi possível criar <code>%s</code>. É preciso verificar as permissões e criar o ficheiro manualmente.';
$lang['i_badhash'] = 'dokuwiki.php não é o original ou não é reconhecido (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - valor ilegal ou vazio';
-$lang['i_success'] = 'A instalação e configuração inicial foram bem sucedidas. Pode remover o install.php. Aceda ao seu novo <a href="doku.php">Wiki</a> a correr o DokuWiki.';
-$lang['i_failure'] = 'Ocorreram alguns erros durante a escrita nos ficheiros de configuração. Poderá ser preciso corrigi-los manualmente antes de poder aceder ao seu novo <a href="doku.php">Wiki</a> a correr o DokuWiki.';
+$lang['i_success'] = 'A instalação e configuração inicial foram bem sucedidas. Pode remover o install.php. Aceda ao seu novo <a href="doku.php?id=wiki:welcome">Wiki</a> a correr o DokuWiki.';
+$lang['i_failure'] = 'Ocorreram alguns erros durante a escrita nos ficheiros de configuração. Poderá ser preciso corrigi-los manualmente antes de poder aceder ao seu novo <a href="doku.php?id=wiki:welcome">Wiki</a> a correr o DokuWiki.';
$lang['i_policy'] = 'Politica ACL inicial';
$lang['i_pol0'] = 'Wiki Aberto (ler, escrever e carregar para todos)';
$lang['i_pol1'] = 'Wiki Público (ler para todos, escrever e carregar para utilizadores inscritos)';
diff --git a/inc/lang/pt/subscr_single.txt b/inc/lang/pt/subscr_single.txt
index 1187b5911..469c6bfb1 100644
--- a/inc/lang/pt/subscr_single.txt
+++ b/inc/lang/pt/subscr_single.txt
@@ -15,7 +15,7 @@ Revisão Nova: @NEWPAGE@
Para cancelar as notificações de página, inicie sessão no wiki em
@DOKUWIKIURL@, visite
-@NEWPAGE@
+@SUBSCRIBE@
e des-subscreva às alterações de página e/ou espaço de nome.
--
diff --git a/inc/lang/ro/lang.php b/inc/lang/ro/lang.php
index 0c7e02605..d6bfcad3a 100644
--- a/inc/lang/ro/lang.php
+++ b/inc/lang/ro/lang.php
@@ -280,8 +280,8 @@ $lang['i_confexists'] = '<code>%s</code> există deja';
$lang['i_writeerr'] = 'Nu s-a putut crea <code>%s</code>. Trebuie să verificaţi drepturile directorului/fişierului şi să creaţi fişierul manual.';
$lang['i_badhash'] = 'dokuwiki.php nu a fost recunoscut sau a fost modificat (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - valoare nepemisă sau neintrodusă';
-$lang['i_success'] = 'Configurarea a fost finalizată cu succes. Acum puteţi sterge fişierul install.php. Continuaţi cu <a href="doku.php">your new DokuWiki</a>.';
-$lang['i_failure'] = 'Au apărut erori la scrierea fişierelor de configurare. Va trebui să le corectaţi manual înainte de a putea folosi <a href="doku.php">your new DokuWiki</a>.';
+$lang['i_success'] = 'Configurarea a fost finalizată cu succes. Acum puteţi sterge fişierul install.php. Continuaţi cu <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.';
+$lang['i_failure'] = 'Au apărut erori la scrierea fişierelor de configurare. Va trebui să le corectaţi manual înainte de a putea folosi <a href="doku.php?id=wiki:welcome">your new DokuWiki</a>.';
$lang['i_policy'] = 'Politica ACL iniţială';
$lang['i_pol0'] = 'Wiki Deschisă (citeşte, scrie şi încarcă oricine)';
$lang['i_pol1'] = 'Wiki Deschisă (citeste oricine, scrie şi încarcă doar utilizatorul înregistrat)';
diff --git a/inc/lang/ru/lang.php b/inc/lang/ru/lang.php
index 5f428b36a..c391bc6a5 100644
--- a/inc/lang/ru/lang.php
+++ b/inc/lang/ru/lang.php
@@ -292,8 +292,8 @@ $lang['i_writeerr'] = 'Не удалось создать <code>%s</c
$lang['i_badhash'] = 'dokuwiki.php не распознан или изменён (хэш=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> — недопустимое или пустое значение';
$lang['i_success'] = 'Конфигурация прошла успешно. Теперь вы можете удалить файл install.php. Переходите к
- <a href="doku.php">своей новой «ДокуВики»</a>.';
-$lang['i_failure'] = 'При записи в файлы конфигурации были обнаружены ошибки. Возможно, вам придётся исправить их вручную, прежде чем вы сможете использовать <a href="doku.php">свою новую «ДокуВики»</a>.';
+ <a href="doku.php?id=wiki:welcome">своей новой «ДокуВики»</a>.';
+$lang['i_failure'] = 'При записи в файлы конфигурации были обнаружены ошибки. Возможно, вам придётся исправить их вручную, прежде чем вы сможете использовать <a href="doku.php?id=wiki:welcome">свою новую «ДокуВики»</a>.';
$lang['i_policy'] = 'Исходная политика прав доступа';
$lang['i_pol0'] = 'Открытая вики (чтение, запись, закачка файлов для всех)';
$lang['i_pol1'] = 'Общедоступная вики (чтение для всех, запись и загрузка файлов для зарегистрированных пользователей)';
diff --git a/inc/lang/sk/lang.php b/inc/lang/sk/lang.php
index b8a947dc3..5bda5fdaf 100644
--- a/inc/lang/sk/lang.php
+++ b/inc/lang/sk/lang.php
@@ -278,8 +278,8 @@ $lang['i_confexists'] = '<code>%s</code> už existuje';
$lang['i_writeerr'] = 'Nie je možné vytvoriť <code>%s</code>. Potrebujete skontrolovať prístupové práva pre adresár/súbor a vytvoriť ho manuálne.';
$lang['i_badhash'] = 'neznámy alebo zmenený súbor dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - nesprávna alebo žiadna hodnota';
-$lang['i_success'] = 'Konfigurácia bola úspešne ukončená. Teraz môžete zmazať súbor install.php. Pokračujte vo <a href="doku.php">vašej novej DokuWiki</a>.';
-$lang['i_failure'] = 'Pri zápise konfiguračného súboru nastali nejaké chyby. Potrebujete ich opraviť manuálne pred tým, ako budete môcť používať <a href="doku.php">vašu novú DokuWiki</a>.';
+$lang['i_success'] = 'Konfigurácia bola úspešne ukončená. Teraz môžete zmazať súbor install.php. Pokračujte vo <a href="doku.php?id=wiki:welcome">vašej novej DokuWiki</a>.';
+$lang['i_failure'] = 'Pri zápise konfiguračného súboru nastali nejaké chyby. Potrebujete ich opraviť manuálne pred tým, ako budete môcť používať <a href="doku.php?id=wiki:welcome">vašu novú DokuWiki</a>.';
$lang['i_policy'] = 'Počiatočná ACL politika';
$lang['i_pol0'] = 'Otvorená Wiki (čítanie, zápis a nahrávanie pre každého)';
$lang['i_pol1'] = 'Verejná Wiki (čítanie pre každého, zápis a nahrávanie pre registrovaných užívateľov)';
diff --git a/inc/lang/sl/lang.php b/inc/lang/sl/lang.php
index 3a4dbd22e..81220b8a2 100644
--- a/inc/lang/sl/lang.php
+++ b/inc/lang/sl/lang.php
@@ -271,8 +271,8 @@ $lang['i_confexists'] = 'Predmet <code>%s</code> že obstaja.';
$lang['i_writeerr'] = 'Ni mogoče ustvariti predmeta <code>%s</code>. Preveriti je treba dovoljenja datotek in map in nato ustvariti datoteko ročno.';
$lang['i_badhash'] = 'nepoznana ali spremenjena datoteka dokuwiki.php (razpršilo=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - neveljavna ali prazna vrednost';
-$lang['i_success'] = 'Nastavitev je uspešno končana. Datoteko install.php lahko sedaj izbrišete. Nadaljujte v <a href="doku.php">novi DokuWiki</a>.';
-$lang['i_failure'] = 'Med zapisovanjem nastavitvenih datotek je prišlo do napak. Preden lahko uporabite vaš <a href="doku.php">DokuWiki</a>, jih je treba odpraviti.';
+$lang['i_success'] = 'Nastavitev je uspešno končana. Datoteko install.php lahko sedaj izbrišete. Nadaljujte v <a href="doku.php?id=wiki:welcome">novi DokuWiki</a>.';
+$lang['i_failure'] = 'Med zapisovanjem nastavitvenih datotek je prišlo do napak. Preden lahko uporabite vaš <a href="doku.php?id=wiki:welcome">DokuWiki</a>, jih je treba odpraviti.';
$lang['i_policy'] = 'Začetna določila ACL';
$lang['i_pol0'] = 'Odprt Wiki (branje, zapis, nalaganje datotek je javno za vse)';
$lang['i_pol1'] = 'Javni Wiki (branje za vse, zapis in nalaganje datotek za prijavljene uporabnike)';
diff --git a/inc/lang/sq/lang.php b/inc/lang/sq/lang.php
index 0e56b89d9..e190d8404 100644
--- a/inc/lang/sq/lang.php
+++ b/inc/lang/sq/lang.php
@@ -223,8 +223,8 @@ $lang['i_confexists'] = '<code>%s</code> ekziston njëherë';
$lang['i_writeerr'] = '<code>%s</code> nuk mundi të krijohej. Duhet të kontrolloni lejet e dirkektorisë/skedarit dhe ta krijoni skedarin manualisht.';
$lang['i_badhash'] = 'dokuwiki.php e panjohur ose e ndryshuar (hash=code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - vlerë e palejuar ose boshe';
-$lang['i_success'] = 'Konfigurimi u mbarua me sukses. Tani mund ta fshini skedarin install.php. Vazhdoni tek <a href="doku.php">DokuWiki juaj i ri.</a>.';
-$lang['i_failure'] = 'Ndodhën disa gabime gjatë shkrimit të skedarit të konfigurimit. Do t\'ju duhet t\'i rregulloni manualisht para se të përdorni <a href="doku.php">DokuWiki-in tuaj të ri.</a>.';
+$lang['i_success'] = 'Konfigurimi u mbarua me sukses. Tani mund ta fshini skedarin install.php. Vazhdoni tek <a href="doku.php?id=wiki:welcome">DokuWiki juaj i ri.</a>.';
+$lang['i_failure'] = 'Ndodhën disa gabime gjatë shkrimit të skedarit të konfigurimit. Do t\'ju duhet t\'i rregulloni manualisht para se të përdorni <a href="doku.php?id=wiki:welcome">DokuWiki-in tuaj të ri.</a>.';
$lang['i_policy'] = 'Veprimi fillestar ACL';
$lang['i_pol0'] = 'Wiki i Hapur (lexim, shkrim, ngarkim për këdo)';
$lang['i_pol1'] = 'Wiki Publike (lexim për këdo, shkrim dhe ngarkim për përdoruesit e regjistruar)';
diff --git a/inc/lang/sq/subscr_single.txt b/inc/lang/sq/subscr_single.txt
index 90520be4f..df28ee176 100644
--- a/inc/lang/sq/subscr_single.txt
+++ b/inc/lang/sq/subscr_single.txt
@@ -15,7 +15,7 @@ Rishikimi i ri: @NEWPAGE@
Për të fshirë lajmërimet e faqes, hyni në wiki tek
@DOKUWIKIURL@ dhe pastaj vizitoni
-@NEWPAGE@
+@SUBSCRIBE@
dhe fshini ndryshimet e faqes dhe/ose hapësirës së emrit.
--
diff --git a/inc/lang/sr/lang.php b/inc/lang/sr/lang.php
index a53f14ac9..d7f594511 100644
--- a/inc/lang/sr/lang.php
+++ b/inc/lang/sr/lang.php
@@ -244,8 +244,8 @@ $lang['i_confexists'] = '<code>%s</code> већ постоји';
$lang['i_writeerr'] = 'Не могу да направим <code>%s</code>. Проверите дозволе а затим ручно направите ову датотеку.';
$lang['i_badhash'] = 'dokuwiki.php није препознат или је измењен (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - недозвољена или празна вредност';
-$lang['i_success'] = 'Подешавања су завршена. Сада можете обрисати датотеку install.php. Наставите у <a href="doku.php">Ваш нови DokuWiki</a>.';
-$lang['i_failure'] = 'Појавили су се проблеми при писању датотеке са подешавањима. Требало би да их ручно исправите пре него што ћете моћи да користите <a href="doku.php">Ваш нови DokuWiki</a>.';
+$lang['i_success'] = 'Подешавања су завршена. Сада можете обрисати датотеку install.php. Наставите у <a href="doku.php?id=wiki:welcome">Ваш нови DokuWiki</a>.';
+$lang['i_failure'] = 'Појавили су се проблеми при писању датотеке са подешавањима. Требало би да их ручно исправите пре него што ћете моћи да користите <a href="doku.php?id=wiki:welcome">Ваш нови DokuWiki</a>.';
$lang['i_policy'] = 'Иницијалне корисничке дозволе';
$lang['i_pol0'] = 'Отворени вики (читање, писање, слање датотека за све)';
$lang['i_pol1'] = 'Јавни вики (читање за све, писање и слање датотека само за регистроване кориснике)';
diff --git a/inc/lang/sv/lang.php b/inc/lang/sv/lang.php
index 0c8f3276d..4c4e060b4 100644
--- a/inc/lang/sv/lang.php
+++ b/inc/lang/sv/lang.php
@@ -172,7 +172,7 @@ $lang['lastmod'] = 'Senast uppdaterad';
$lang['by'] = 'av';
$lang['deleted'] = 'raderad';
$lang['created'] = 'skapad';
-$lang['restored'] = 'tidigare version återställd';
+$lang['restored'] = 'tidigare version återställd (%s)';
$lang['external_edit'] = 'extern redigering';
$lang['summary'] = 'Redigeringskommentar';
$lang['noflash'] = '<a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a> behövs för att visa detta innehåll.';
@@ -246,9 +246,9 @@ $lang['i_writeerr'] = 'Kan inte skapa <code>%s</code>. Kontrollera fi
$lang['i_badhash'] = 'okänd eller ändrad dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - felaktig eller blank';
$lang['i_success'] = 'Konfigurationen avslutades utan fel. Du kan radera filen install.php nu. Fortsätt till
- <a href="doku.php">din nya DokuWiki</a>.';
+ <a href="doku.php?id=wiki:welcome">din nya DokuWiki</a>.';
$lang['i_failure'] = 'Fel uppstod vid skrivning av konfigurationsfilerna. Du kan behöva ordna till dem manuellt innan
- du kan använda <a href="doku.php">din nya DokuWiki</a>.';
+ du kan använda <a href="doku.php?id=wiki:welcome">din nya DokuWiki</a>.';
$lang['i_policy'] = 'Initial ACL-policy';
$lang['i_pol0'] = 'Öppen wiki (alla får läsa, skriva och ladda upp filer)';
$lang['i_pol1'] = 'Publik wiki (alla får läsa, registrerade användare för skriva och ladda upp filer)';
diff --git a/inc/lang/tr/lang.php b/inc/lang/tr/lang.php
index 77518ac36..5430905b1 100644
--- a/inc/lang/tr/lang.php
+++ b/inc/lang/tr/lang.php
@@ -8,6 +8,7 @@
* @author Cihan Kahveci <kahvecicihan@gmail.com>
* @author Yavuz Selim <yavuzselim@gmail.com>
* @author Caleb Maclennan <caleb@alerque.com>
+ * @author farukerdemoncel@gmail.com
*/
$lang['encoding'] = 'utf-8';
$lang['direction'] = 'ltr';
@@ -43,11 +44,14 @@ $lang['btn_backtomedia'] = 'Çokluortam dosyası seçimine dön';
$lang['btn_subscribe'] = 'Sayfa Değişikliklerini Bildir';
$lang['btn_profile'] = 'Kullanıcı Bilgilerini Güncelle';
$lang['btn_reset'] = 'Sıfırla';
+$lang['btn_resendpwd'] = 'Yeni şifre belirle';
$lang['btn_draft'] = 'Taslağı düzenle';
$lang['btn_recover'] = 'Taslağı geri yükle';
$lang['btn_draftdel'] = 'Taslağı sil';
$lang['btn_revert'] = 'Geri Yükle';
$lang['btn_register'] = 'Kayıt ol';
+$lang['btn_apply'] = 'Uygula';
+$lang['btn_media'] = 'Çokluortam Yöneticisi';
$lang['loggedinas'] = 'Giriş ismi';
$lang['user'] = 'Kullanıcı ismi';
$lang['pass'] = 'Parola';
@@ -77,6 +81,7 @@ $lang['profnoempty'] = 'Boş isim veya e-posta adresine izin verilmiyo
$lang['profchanged'] = 'Kullanıcı bilgileri başarıyla değiştirildi.';
$lang['pwdforget'] = 'Parolanızı mı unuttunuz? Yeni bir parola alın';
$lang['resendna'] = 'Bu wiki parolayı tekrar göndermeyi desteklememektedir.';
+$lang['resendpwd'] = 'İçin yeni şifre belirle';
$lang['resendpwdmissing'] = 'Üzgünüz, tüm alanları doldurmalısınız.';
$lang['resendpwdnouser'] = 'Üzgünüz, veritabanımızda bu kullanıcıyı bulamadık.';
$lang['resendpwdbadauth'] = 'Üzgünüz, bu doğrulama kodu doğru değil. Doğrulama linkini tam olarak kullandığınıza emin olun.';
@@ -91,7 +96,7 @@ $lang['txt_filename'] = 'Dosya adı (zorunlu değil)';
$lang['txt_overwrt'] = 'Mevcut dosyanın üstüne yaz';
$lang['lockedby'] = 'Şu an şunun tarafından kilitli:';
$lang['lockexpire'] = 'Kilitin açılma tarihi:';
-$lang['js']['willexpire'] = 'Bu sayfayı değiştirme kilidinin süresi yaklaşık bir dakika içinde geçecek.\nÇakışmaları önlemek için önizleme tuşunu kullanarak kilit sayacını sıfırla.';
+$lang['js']['willexpire'] = 'Bu sayfayı değiştirme kilidinin süresi yaklaşık bir dakika içinde geçecek.\nÇakışmaları önlemek için önizleme tuşunu kullanarak kilit sayacını sıfırla.';
$lang['js']['notsavedyet'] = 'Kaydedilmemiş değişiklikler kaybolacak.
Devam etmek istiyor musunuz?';
$lang['js']['searchmedia'] = 'Dosyalar için Ara';
@@ -122,6 +127,14 @@ $lang['js']['nosmblinks'] = 'Windows paylaşımı sadece Microsoft Internet
$lang['js']['linkwiz'] = 'Bağlantı sihirbazı';
$lang['js']['linkto'] = 'Bağlantı:';
$lang['js']['del_confirm'] = 'Bu girişi sil?';
+$lang['js']['restore_confirm'] = 'Bu sürüme geri dönmek istediğinizden emin misiniz?';
+$lang['js']['media_diff'] = 'Farkları gör:';
+$lang['js']['media_select'] = 'Dosyalar seç...';
+$lang['js']['media_upload_btn'] = 'Yükle';
+$lang['js']['media_done_btn'] = 'Bitti';
+$lang['js']['media_drop'] = 'Yüklemek istediğiniz dosyaları buraya bırakın';
+$lang['js']['media_cancel'] = 'kaldır';
+$lang['js']['media_overwrt'] = 'Var olan dosyaların üzerine yaz';
$lang['rssfailed'] = 'Bu beslemeyi çekerken hata oluştu: ';
$lang['nothingfound'] = 'Hiçbir şey yok.';
$lang['mediaselect'] = 'Çokluortam dosyası seçimi';
@@ -172,6 +185,9 @@ $lang['mail_newpage'] = 'sayfa eklenme:';
$lang['mail_changed'] = 'sayfa değiştirilme:';
$lang['mail_new_user'] = 'yeni kullanıcı';
$lang['mail_upload'] = 'dosya yüklendi:';
+$lang['pages_changes'] = 'Sayfalar';
+$lang['media_changes'] = 'Çokluortam dosyaları';
+$lang['both_changes'] = 'Sayfalar ve çoklu ortam dosyaları';
$lang['qb_bold'] = 'Kalın Yazı';
$lang['qb_italic'] = 'Eğik Yazı';
$lang['qb_underl'] = 'Altı Çizgili Yazı';
@@ -209,8 +225,14 @@ $lang['img_copyr'] = 'Telif Hakkı';
$lang['img_format'] = 'Biçim';
$lang['img_camera'] = 'Fotoğraf Makinası';
$lang['img_keywords'] = 'Anahtar Sözcükler';
+$lang['img_width'] = 'Genişlik';
+$lang['img_height'] = 'Yükseklik';
+$lang['img_manager'] = 'Ortam oynatıcısında göster';
+$lang['subscr_m_subscribe'] = 'Kayıt ol';
+$lang['subscr_m_receive'] = 'Al';
$lang['authmodfailed'] = 'Yanlış kullanıcı onaylama ayarı. Lütfen Wiki yöneticisine bildiriniz.';
$lang['authtempfail'] = 'Kullanıcı doğrulama geçici olarak yapılamıyor. Eğer bu durum devam ederse lütfen Wiki yöneticine haber veriniz.';
+$lang['authpwdexpire'] = 'Şifreniz %d gün sonra geçersiz hale gelecek, yakın bir zamanda değiştirmelisiniz.';
$lang['i_chooselang'] = 'Dili seçiniz';
$lang['i_installer'] = 'Dokuwiki Kurulum Sihirbazı';
$lang['i_wikiname'] = 'Wiki Adı';
@@ -232,4 +254,31 @@ $lang['i_pol0'] = 'Tamamen Açık Wiki (herkes okuyabilir, yazabi
$lang['i_pol1'] = 'Açık Wiki (herkes okuyabilir, ancak sadece üye olanlar yazabilir ve dosya yükleyebilir)';
$lang['i_pol2'] = 'Kapalı Wiki (sadece üye olanlar okuyabilir, yazabilir ve dosya yükleyebilir)';
$lang['i_retry'] = 'Tekrar Dene';
+$lang['i_license'] = 'Lütfen içeriği hangi lisans altında yayınlamak istediğniizi belirtin:';
$lang['recent_global'] = '<b>%s</b> namespace\'i içerisinde yapılan değişiklikleri görüntülemektesiniz. Wiki\'deki tüm değişiklikleri de <a href="%s">bu adresten</a> görebilirsiniz. ';
+$lang['years'] = '%d yıl önce';
+$lang['months'] = '%d ay önce';
+$lang['weeks'] = '%d hafta önce';
+$lang['days'] = '%d gün önce';
+$lang['hours'] = '%d saat önce';
+$lang['minutes'] = '%d dakika önce';
+$lang['seconds'] = '%d saniye önce';
+$lang['wordblock'] = 'Değişikliğiniz kaydedilmedi çünkü istenmeyen mesaj içeriyor (spam).';
+$lang['media_uploadtab'] = 'Karşıya yükle';
+$lang['media_searchtab'] = 'Ara';
+$lang['media_file'] = 'Dosya';
+$lang['media_viewtab'] = 'Görünüm';
+$lang['media_edittab'] = 'Düzenle';
+$lang['media_historytab'] = 'Geçmiş';
+$lang['media_list_thumbs'] = 'Küçük resimler';
+$lang['media_list_rows'] = 'Satırlar';
+$lang['media_sort_name'] = 'İsim';
+$lang['media_sort_date'] = 'Tarih';
+$lang['media_files'] = '%s deki dosyalar';
+$lang['media_upload'] = '%s dizinine yükle';
+$lang['media_search'] = '%s dizininde ara';
+$lang['media_view'] = '%s';
+$lang['media_edit'] = 'Düzenle %s';
+$lang['media_history'] = 'Geçmiş %s';
+$lang['media_perm_upload'] = 'Üzgünüm, karşıya dosya yükleme yetkiniz yok.';
+$lang['media_restore'] = 'Bu sürümü eski haline getir';
diff --git a/inc/lang/tr/resetpwd.txt b/inc/lang/tr/resetpwd.txt
new file mode 100644
index 000000000..1ed758693
--- /dev/null
+++ b/inc/lang/tr/resetpwd.txt
@@ -0,0 +1,3 @@
+ ====== Yeni şifre belirle ======
+
+Lütfen bu wiki hesabınız için yeni bir şifre belirleyin. \ No newline at end of file
diff --git a/inc/lang/uk/lang.php b/inc/lang/uk/lang.php
index b06cb9158..5274a4210 100644
--- a/inc/lang/uk/lang.php
+++ b/inc/lang/uk/lang.php
@@ -253,9 +253,9 @@ $lang['i_writeerr'] = 'Неможливо створити <code>%s</
$lang['i_badhash'] = 'Невпізнаний або модифікований dokuwiki.php (hash=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - невірне або пусте значення.';
$lang['i_success'] = 'Налаштування завершено. Ви можете знищити файл install.php.
-Перейдіть до <a href="doku.php">вашої нової ДокуВікі</a>';
+Перейдіть до <a href="doku.php?id=wiki:welcome">вашої нової ДокуВікі</a>';
$lang['i_failure'] = 'При збереженні файлу конфігурації виникли помилки. Можливо вам доведеться виправити їх самостійно
-до початку використання <a href="doku.php">вашої нової ДокуВікі</a>.';
+до початку використання <a href="doku.php?id=wiki:welcome">вашої нової ДокуВікі</a>.';
$lang['i_policy'] = 'Початкова політика ACL';
$lang['i_pol0'] = 'Відкрита Вікі (читання, запис та завантаження файлів для всіх)';
$lang['i_pol1'] = 'Публічна Вікі (читання для всіх, запис та завантаження для зареєстрованих користувачів)';
diff --git a/inc/lang/zh-tw/adminplugins.txt b/inc/lang/zh-tw/adminplugins.txt
index fb1999269..6d21ac2cd 100644
--- a/inc/lang/zh-tw/adminplugins.txt
+++ b/inc/lang/zh-tw/adminplugins.txt
@@ -1 +1 @@
-===== 外加插件 ===== \ No newline at end of file
+===== 附加元件 ===== \ No newline at end of file
diff --git a/inc/lang/zh-tw/backlinks.txt b/inc/lang/zh-tw/backlinks.txt
index 5b36728e7..6a8bf8896 100644
--- a/inc/lang/zh-tw/backlinks.txt
+++ b/inc/lang/zh-tw/backlinks.txt
@@ -1,4 +1,4 @@
====== 反向連結 ======
-這裡是引用、連結到目前頁面的頁面清單。
+這是引用、連結到目前頁面的頁面清單。
diff --git a/inc/lang/zh-tw/diff.txt b/inc/lang/zh-tw/diff.txt
index 17fad7ba0..e2c05001f 100644
--- a/inc/lang/zh-tw/diff.txt
+++ b/inc/lang/zh-tw/diff.txt
@@ -1,3 +1,3 @@
====== 差異處 ======
-這裏顯示二個版本的差異處。 \ No newline at end of file
+這裏顯示兩個版本的差異處。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/edit.txt b/inc/lang/zh-tw/edit.txt
index bbe5bb8ed..f6b74794f 100644
--- a/inc/lang/zh-tw/edit.txt
+++ b/inc/lang/zh-tw/edit.txt
@@ -1 +1 @@
-編輯本頁並按下''儲存''即可。可在[[wiki:syntax|維基語法]]找到語法說明。請只在能讓本文品質「**更好**」時才編輯。如果只是要測試,請使用 [[playground:playground|遊樂場]]。
+編輯本頁後,請按下「儲存」按鈕。若要參看語法說明,請到[[wiki:syntax|語法]]頁。請只在能讓本文品質**更好**時才編輯。如果只是要測試,請移玉步至 [[playground:playground|遊樂場]]。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/editrev.txt b/inc/lang/zh-tw/editrev.txt
index 96f9a7c6a..98a800ab1 100644
--- a/inc/lang/zh-tw/editrev.txt
+++ b/inc/lang/zh-tw/editrev.txt
@@ -1,2 +1,2 @@
-**您目前載入的是本份文件的舊版!** 您如果存檔,這些資料就會被存成另一份。
+**您目前載入的是本份文件的舊版!** 您如果存檔,這些舊版資料就會變成最新版本。
----
diff --git a/inc/lang/zh-tw/index.txt b/inc/lang/zh-tw/index.txt
index bba277041..1b89e0c5d 100644
--- a/inc/lang/zh-tw/index.txt
+++ b/inc/lang/zh-tw/index.txt
@@ -1,3 +1,3 @@
====== 站台地圖 ======
-這個站台地圖列出了所有允許的頁面,依 [[doku>namespaces|分類空間]] 排序。 \ No newline at end of file
+這個站台地圖列出了所有允許的頁面,依 [[doku>namespaces|分類名稱]] 排序。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/install.html b/inc/lang/zh-tw/install.html
index 2a8b1aac3..9a0d1dcd9 100644
--- a/inc/lang/zh-tw/install.html
+++ b/inc/lang/zh-tw/install.html
@@ -1,8 +1,8 @@
<p>本頁面旨在幫助您完成第一次安装和設定 <a href="http://dokuwiki.org">Dokuwiki</a>。關於安裝工具的更多訊息請參閱 <a href="http://dokuwiki.org/installer">官方文檔頁面</a>。</p>
-<p>DokuWiki 使用普通檔案儲存維基頁面以及與頁面相關的訊息(例如:圖像,搜尋索引,修訂記錄等)。為了正常運作,DokuWiki <strong>必須</strong> 擁有針對那些路徑和檔案的寫入權限。本安裝工具無法設定目錄權限,這通常要透過命令行、FTP 或您主機上的控制台(如cPanel)進行。</p>
+<p>DokuWiki 使用普通檔案來儲存 wiki 頁面,以及與頁面相關的訊息(例如:圖像、搜尋索引、修訂記錄等)。為了正常運作,DokuWiki <strong>必須</strong> 擁有針對那些路徑和檔案的寫入權限。本安裝工具無法設定目錄權限,這通常要透過命令行、FTP 或您主機上的控制台(如cPanel)進行。</p>
-<p>本安裝工具將設定您的 DokuWiki 用於 <abbr title="訪問控制列表">ACL</abbr> 的設定檔,它能讓管理員登入並使用「管理」功能來安裝插件、管理用户、管理訪問權限和其他設定設定。它並不是 DokuWiki 正常運作所必須,但安裝之後將更方便管理。</p>
+<p>本安裝工具將設定您的 DokuWiki 用於 <abbr title="訪問控制列表">ACL</abbr> 的設定檔,它能讓管理員登入並使用「管理」功能來安裝附加元件、管理使用者、管理訪問權限和其他設定設定。它並不是 DokuWiki 正常運作所必須,但安裝之後將更方便管理。</p>
-<p>有經驗的用戶或有特殊需求的用戶請參閱更詳細的 <a href="http://dokuwiki.org/install">安裝指南</a>
+<p>有經驗的或有特殊需求的使用者,請參閱更詳細的 <a href="http://dokuwiki.org/install">安裝指南</a>
和 <a href="http://dokuwiki.org/config">設定</a>。</p> \ No newline at end of file
diff --git a/inc/lang/zh-tw/lang.php b/inc/lang/zh-tw/lang.php
index 2cceb4012..ddb35617e 100644
--- a/inc/lang/zh-tw/lang.php
+++ b/inc/lang/zh-tw/lang.php
@@ -11,6 +11,7 @@
* @author Danny Lin
* @author Shuo-Ting Jian <shoting@gmail.com>
* @author syaoranhinata@gmail.com
+ * @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
$lang['encoding'] = 'utf-8';
$lang['direction'] = 'ltr';
@@ -19,7 +20,7 @@ $lang['doublequoteclosing'] = '”';
$lang['singlequoteopening'] = '‘';
$lang['singlequoteclosing'] = '’';
$lang['apostrophe'] = '’';
-$lang['btn_edit'] = '編修本頁';
+$lang['btn_edit'] = '編輯本頁';
$lang['btn_source'] = '顯示原始碼';
$lang['btn_show'] = '顯示頁面';
$lang['btn_create'] = '建立此頁';
@@ -34,7 +35,7 @@ $lang['btn_recent'] = '最近更新';
$lang['btn_upload'] = '上傳';
$lang['btn_cancel'] = '取消';
$lang['btn_index'] = '站台地圖';
-$lang['btn_secedit'] = '改這段';
+$lang['btn_secedit'] = '編輯此段';
$lang['btn_login'] = '登入';
$lang['btn_logout'] = '登出';
$lang['btn_admin'] = '管理選單';
@@ -61,40 +62,40 @@ $lang['newpass'] = '新密碼';
$lang['oldpass'] = '目前密碼';
$lang['passchk'] = '確認密碼';
$lang['remember'] = '記住帳號密碼';
-$lang['fullname'] = '真實姓名';
+$lang['fullname'] = '姓名';
$lang['email'] = '電郵';
$lang['profile'] = '使用者個人資料';
$lang['badlogin'] = '很抱歉,您的使用者名稱或密碼可能有錯誤。';
$lang['minoredit'] = '小修改';
$lang['draftdate'] = '草稿已自動存檔於';
-$lang['nosecedit'] = '頁面在這之間已被修改,過時的區段資料已載入全頁取代。';
+$lang['nosecedit'] = '在您編輯期間,其他使用者修改過本頁面。區段資料已逾時,因此系統載入了全頁,以取代之。';
$lang['regmissing'] = '很抱歉,所有欄位都要填寫。';
-$lang['reguexists'] = '很抱歉,本帳號已被註冊。';
-$lang['regsuccess'] = '使用者已建立,密碼已寄發至該 email。';
-$lang['regsuccess2'] = '使用者已建立。';
+$lang['reguexists'] = '很抱歉,有人已使用了這個帳號。';
+$lang['regsuccess'] = '使用者帳號已建立,密碼已寄發至該電郵。';
+$lang['regsuccess2'] = '使用者帳號已建立。';
$lang['regmailfail'] = '寄出密碼信似乎發生錯誤,請跟管理員聯絡!';
-$lang['regbadmail'] = '您輸入的 email 似乎不對,如果您認為是正確的,請與管理員聯絡。';
+$lang['regbadmail'] = '您輸入的電郵似乎不對,如果您認為是正確的,請與管理員聯絡。';
$lang['regbadpass'] = '兩次輸入的密碼不一致,請再試一次。';
$lang['regpwmail'] = '您的 DokuWiki 帳號密碼';
$lang['reghere'] = '您還沒有帳號嗎?註冊一個吧。';
-$lang['profna'] = '本維基不開放修改個人資料。';
-$lang['profnochange'] = '未做任何變更。';
+$lang['profna'] = '在本 wiki 上,不能修改個人資料。';
+$lang['profnochange'] = '並未作任何變更。';
$lang['profnoempty'] = '帳號或電郵地址不可空白!';
-$lang['profchanged'] = '個人資料已成功更新。';
+$lang['profchanged'] = '個人資料已更新。';
$lang['pwdforget'] = '忘記密碼了?索取新密碼!';
-$lang['resendna'] = '本維基不開放重寄密碼。';
+$lang['resendna'] = '本 wiki 並不支援重寄密碼。';
$lang['resendpwd'] = '設定新密碼供';
$lang['resendpwdmissing'] = '抱歉,您必須填寫所有欄位。';
$lang['resendpwdnouser'] = '抱歉,資料庫內找不到這個使用者。';
$lang['resendpwdbadauth'] = '抱歉,認證碼無效。請確認您使用了完整的確認連結。';
$lang['resendpwdconfirm'] = '確認連結已通過郵件發送給您了。';
$lang['resendpwdsuccess'] = '您的新密碼已寄出。';
-$lang['license'] = '若未特別註明,此維基上的內容都是採用以下授權方式:';
+$lang['license'] = '若無特別註明,本 wiki 上的內容都是採用以下授權方式:';
$lang['licenseok'] = '注意:編輯此頁面表示您已同意以下的授權方式:';
$lang['searchmedia'] = '搜尋檔名:';
$lang['searchmedia_in'] = '在 %s 裏搜尋';
$lang['txt_upload'] = '請選擇要上傳的檔案';
-$lang['txt_filename'] = '請輸入要存在維基內的檔案名稱 (非必要)';
+$lang['txt_filename'] = '請輸入要上傳至本 wiki 的檔案名稱 (非必要)';
$lang['txt_overwrt'] = '是否要覆蓋原有檔案';
$lang['maxuploadsize'] = '每個上傳檔案不可大於 %s 。';
$lang['lockedby'] = '目前已被下列人員鎖定';
@@ -135,7 +136,7 @@ $lang['js']['media_diff'] = '檢視差異:';
$lang['js']['media_diff_both'] = '並排';
$lang['js']['media_diff_opacity'] = '重疊';
$lang['js']['media_diff_portions'] = '滑動';
-$lang['js']['media_select'] = '選擇檔案…';
+$lang['js']['media_select'] = '選擇檔案……';
$lang['js']['media_upload_btn'] = '上傳';
$lang['js']['media_done_btn'] = '完成';
$lang['js']['media_drop'] = '拖拉檔案到此上傳';
@@ -145,27 +146,27 @@ $lang['rssfailed'] = '擷取 RSS 饋送檔時發生錯誤:';
$lang['nothingfound'] = '沒找到任何結果。';
$lang['mediaselect'] = '媒體檔案';
$lang['fileupload'] = '上傳媒體檔案';
-$lang['uploadsucc'] = '上傳成功';
-$lang['uploadfail'] = '上傳失敗。似乎是權限錯誤?';
+$lang['uploadsucc'] = '已上傳';
+$lang['uploadfail'] = '無法上傳。是否因權限錯誤?';
$lang['uploadwrong'] = '拒絕上傳。這個副檔名被禁止了!';
$lang['uploadexist'] = '檔案已存在,未處理。';
$lang['uploadbadcontent'] = '上傳檔案的內容不符合 %s 檔的副檔名。';
-$lang['uploadspam'] = '這次的上傳被垃圾訊息黑名單阻檔了。';
-$lang['uploadxss'] = '這次的上傳因可能的惡意的內容而被阻檔。';
-$lang['uploadsize'] = '上傳的檔案太大了 (最大:%s)';
+$lang['uploadspam'] = '是次上傳被垃圾訊息黑名單阻檔了。';
+$lang['uploadxss'] = '因可能含有惡意內容,是次上傳已被阻檔。';
+$lang['uploadsize'] = '上傳的檔案太大了 (最大為:%s)';
$lang['deletesucc'] = '檔案 "%s" 已刪除。';
$lang['deletefail'] = '檔案 "%s" 無法刪除,請檢查權限定。';
-$lang['mediainuse'] = '檔案 "%s" 未刪除,因為它正被使用。';
-$lang['namespaces'] = '分類空間';
+$lang['mediainuse'] = '檔案 "%s" 仍在使用,並未刪除。';
+$lang['namespaces'] = '分類名稱';
$lang['mediafiles'] = '可用的檔案有';
$lang['accessdenied'] = '您不可以檢視此頁面。';
$lang['mediausage'] = '使用以下的語法來連結此檔案:';
$lang['mediaview'] = '檢視原始檔案';
$lang['mediaroot'] = 'root';
-$lang['mediaupload'] = '上傳檔案至目前的分類空間。要建立子分類空間,將其名稱加在「上傳並重命名為」檔案名的前面,並用英文冒號隔開。';
+$lang['mediaupload'] = '上傳檔案至目前分類名稱之下。要建立子分類名稱,請將其名稱加在「上傳並重命名為」檔案名的前面,並用英文冒號隔開。';
$lang['mediaextchange'] = '檔案類型已由 .%s 變更為 .%s !';
$lang['reference'] = '引用到本頁的,合計有';
-$lang['ref_inuse'] = '此檔案無法刪除,因為它正被以下頁面使用:';
+$lang['ref_inuse'] = '此檔案無法刪除,因以下頁面正在使用它:';
$lang['ref_hidden'] = '一些參考內容位於您沒有讀取權限的頁面中';
$lang['hits'] = '個符合';
$lang['quickhits'] = '符合的頁面名稱';
@@ -175,12 +176,12 @@ $lang['yours'] = '您的版本';
$lang['diff'] = '顯示與目前版本的差異';
$lang['diff2'] = '顯示選擇版本間的差異';
$lang['difflink'] = '連向這個比對檢視';
-$lang['diff_type'] = '檢視差異:';
+$lang['diff_type'] = '檢視差異:';
$lang['diff_inline'] = '行內';
$lang['diff_side'] = '並排';
$lang['line'] = '行';
$lang['breadcrumb'] = '足跡';
-$lang['youarehere'] = '您在這裡';
+$lang['youarehere'] = '您在這裏';
$lang['lastmod'] = '上一次變更';
$lang['by'] = '由';
$lang['deleted'] = '移除';
@@ -188,17 +189,17 @@ $lang['created'] = '建立';
$lang['restored'] = '恢復為舊版';
$lang['external_edit'] = '外部編輯';
$lang['summary'] = '編輯摘要';
-$lang['noflash'] = '顯示此內容需要 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash Plugin</a>';
+$lang['noflash'] = '顯示此內容需要 <a href="http://www.adobe.com/products/flashplayer/">Adobe Flash 附加元件</a>。';
$lang['download'] = '下載程式碼片段';
$lang['tools'] = '工具';
-$lang['user_tools'] = '用戶工具';
+$lang['user_tools'] = '使用者工具';
$lang['site_tools'] = '網站工具';
$lang['page_tools'] = '頁面工具';
$lang['skip_to_content'] = '跳至內容';
$lang['sidebar'] = '側欄';
$lang['mail_newpage'] = '增加的頁面:';
$lang['mail_changed'] = '變更的頁面:';
-$lang['mail_subscribe_list'] = '分類空間中更動的頁面:';
+$lang['mail_subscribe_list'] = '分類名稱中變更的頁面:';
$lang['mail_new_user'] = '新使用者:';
$lang['mail_upload'] = '已上傳檔案:';
$lang['changes_type'] = '檢視最近更新類型';
@@ -229,10 +230,10 @@ $lang['qb_media'] = '加入圖片或檔案';
$lang['qb_sig'] = '插入簽名';
$lang['qb_smileys'] = '表情符號';
$lang['qb_chars'] = '特殊字元';
-$lang['upperns'] = '前往父分類空間';
+$lang['upperns'] = '前往父分類名稱';
$lang['admin_register'] = '新增使用者';
$lang['metaedit'] = '編輯後設資料';
-$lang['metasaveerr'] = '後設資料寫入失敗';
+$lang['metasaveerr'] = '後設資料無法寫入';
$lang['metasaveok'] = '後設資料已儲存';
$lang['img_backto'] = '回上一頁';
$lang['img_title'] = '標題';
@@ -253,9 +254,9 @@ $lang['subscr_subscribe_error'] = '將 %s 加入至 %s 的訂閱列表時發生
$lang['subscr_subscribe_noaddress'] = '沒有與您登入相關的地址,無法將您加入訂閱列表';
$lang['subscr_unsubscribe_success'] = '已將 %s 移除自 %s 的訂閱列表';
$lang['subscr_unsubscribe_error'] = '將 %s 移除自 %s 的訂閱列表時發生錯誤';
-$lang['subscr_already_subscribed'] = '%s 已經被 %s 訂閱了';
-$lang['subscr_not_subscribed'] = '%s 尚未被 %s 訂閱';
-$lang['subscr_m_not_subscribed'] = '您尚未訂閱目前的頁面或分類空間。';
+$lang['subscr_already_subscribed'] = '%s 已經獲 %s 訂閱了';
+$lang['subscr_not_subscribed'] = '%s 尚未獲 %s 訂閱';
+$lang['subscr_m_not_subscribed'] = '您尚未訂閱目前的頁面或分類名稱。';
$lang['subscr_m_new_header'] = '加入訂閱';
$lang['subscr_m_current_header'] = '目前訂閱';
$lang['subscr_m_unsubscribe'] = '取消訂閱';
@@ -264,34 +265,34 @@ $lang['subscr_m_receive'] = '接收';
$lang['subscr_style_every'] = '每次更改都發送信件';
$lang['subscr_style_digest'] = '對每個頁面發送更改的摘要信件 (每 %.2f 天)';
$lang['subscr_style_list'] = '自上次發信以來更改的頁面的列表 (每 %.2f 天)';
-$lang['authmodfailed'] = '帳號認證的設定不正確,請通知該維基管理員。';
-$lang['authtempfail'] = '帳號認證目前暫不提供,若本狀況持續發生的話,請通知該維基管理員。';
+$lang['authmodfailed'] = '帳號認證的設定不正確,請通知該本 wiki 管理員。';
+$lang['authtempfail'] = '帳號認證目前暫不提供。若本狀況持續,請通知本 wiki 管理員。';
$lang['authpwdexpire'] = '您的密碼將在 %d 天內到期,請馬上更換新密碼。';
$lang['i_chooselang'] = '選擇您的語系';
$lang['i_installer'] = 'DokuWiki 安裝工具';
-$lang['i_wikiname'] = '維基名稱';
+$lang['i_wikiname'] = '本 wiki 的名稱';
$lang['i_enableacl'] = '啟用 ACL (建議)';
-$lang['i_superuser'] = '超級用戶';
+$lang['i_superuser'] = '超級使用者';
$lang['i_problems'] = '安裝程式發現如下的問題。您必須修正它們才能繼續。';
$lang['i_modified'] = '出於安全考量,本腳本只能用於安裝全新且未修改的 Dokuwiki。
您可以重新解壓下載的封包或查閱完整的<a href=\"http://dokuwiki.org/install\">Dokuwiki 安裝指南</a>';
$lang['i_funcna'] = 'PHP 函數 <code>%s</code> 無法使用。也許您的主機供應者基於某些理由停用了它?';
$lang['i_phpver'] = '您的 PHP 版本 <code>%s</code> 比需要的版本 <code>%s</code> 還低。您必須更新您的PHP。';
-$lang['i_permfail'] = '<code>%s</code> 無法被 DokuWiki 寫入。您必須修正該目錄的權限!';
+$lang['i_permfail'] = '<code>%s</code> 無法經由 DokuWiki 寫入。您必須修正該目錄的權限!';
$lang['i_confexists'] = '<code>%s</code> 已經存在';
$lang['i_writeerr'] = '無法建立 <code>%s</code>。您必須檢查目錄/檔案的權限並手動建立該檔案。';
-$lang['i_badhash'] = '無法辨識或被變更的 dokuwiki.php (hash=<code>%s</code>)';
-$lang['i_badval'] = '<code>%s</code> - 非法或空白的值';
-$lang['i_success'] = '設定已成功完成。您現在可以刪除 install.php 檔案。繼續到
+$lang['i_badhash'] = '無法辨識或已遭修改的 dokuwiki.php (hash=<code>%s</code>)';
+$lang['i_badval'] = '<code>%s</code> —— 非法或空白的值';
+$lang['i_success'] = '設定已完成。您現在可以刪除 install.php 檔案。繼續到
<a href="doku.php">您的新 DokuWiki</a>.';
$lang['i_failure'] = '寫入設定檔時發生了一些錯誤。您必須在使用<a href="doku.php">您的新 Dokuwiki</a> 之前手動修正它們。';
$lang['i_policy'] = '初步的 ACL 政策';
-$lang['i_pol0'] = '開放的維基 (任何人可讀取、寫入、上傳)';
-$lang['i_pol1'] = '公開的維基 (任何人可讀取,註冊使用者可寫入與上傳)';
-$lang['i_pol2'] = '封閉的維基 (只有註冊使用者可讀取、寫入、上傳)';
+$lang['i_pol0'] = '開放的 wiki (任何人可讀取、寫入、上傳)';
+$lang['i_pol1'] = '公開的 wiki (任何人可讀取,註冊使用者可寫入與上傳)';
+$lang['i_pol2'] = '封閉的 wiki (只有註冊使用者可讀取、寫入、上傳)';
$lang['i_retry'] = '重試';
$lang['i_license'] = '請選擇您想要的內容發布許可協議:';
-$lang['recent_global'] = '您正在閱讀分類空間: <b>%s</b> 中的變更。您亦可觀看整個維基的<a href="%s">最近更新</a>。';
+$lang['recent_global'] = '您正在閱讀分類名稱: <b>%s</b> 中的變更。您亦可觀看本 wiki <a href="%s">所有的最近更新</a>。';
$lang['years'] = '%d 年前';
$lang['months'] = '%d 個月前';
$lang['weeks'] = '%d 週前';
@@ -299,7 +300,7 @@ $lang['days'] = '%d 天前';
$lang['hours'] = '%d 個小時前';
$lang['minutes'] = '%d 分鐘前';
$lang['seconds'] = '%s 秒鐘前';
-$lang['wordblock'] = '您的更改沒有被儲存,因为它包含被阻擋的文字 (垃圾訊息)。';
+$lang['wordblock'] = '無法儲存您的更改,因為它含有受阻擋的文字 (垃圾訊息)。';
$lang['media_uploadtab'] = '上傳';
$lang['media_searchtab'] = '搜尋';
$lang['media_file'] = '檔案';
@@ -310,7 +311,7 @@ $lang['media_list_thumbs'] = '縮圖';
$lang['media_list_rows'] = '列表';
$lang['media_sort_name'] = '名稱';
$lang['media_sort_date'] = '日期';
-$lang['media_namespaces'] = '選擇分類空間';
+$lang['media_namespaces'] = '選擇分類名稱';
$lang['media_files'] = '在 %s 中的檔案';
$lang['media_upload'] = '上傳至 %s';
$lang['media_search'] = '在 %s 中搜尋';
diff --git a/inc/lang/zh-tw/locked.txt b/inc/lang/zh-tw/locked.txt
index e13fdc890..819e59e2f 100644
--- a/inc/lang/zh-tw/locked.txt
+++ b/inc/lang/zh-tw/locked.txt
@@ -1,3 +1,3 @@
====== 頁面鎖定 ======
-本頁目前正由其他使用者編修中,您必須等他完成編輯或等鎖定時間過去。
+其他使用者正在編輯本頁,您必須等他完成編輯或等鎖定時間過去。
diff --git a/inc/lang/zh-tw/login.txt b/inc/lang/zh-tw/login.txt
index 058cc5712..b82f08a20 100644
--- a/inc/lang/zh-tw/login.txt
+++ b/inc/lang/zh-tw/login.txt
@@ -1,5 +1,4 @@
====== 登入 ======
-您尚未登入,請輸入您的使用者名稱和密碼。 另外,瀏覽器需要打開 cookies 設定以進行登入。
-
+您尚未登入,請輸入您的使用者名稱和密碼。 另外,瀏覽器需要啟用 cookies 以登入本 wiki。
diff --git a/inc/lang/zh-tw/mailtext.txt b/inc/lang/zh-tw/mailtext.txt
index 3b6ece377..2a402c2fb 100644
--- a/inc/lang/zh-tw/mailtext.txt
+++ b/inc/lang/zh-tw/mailtext.txt
@@ -2,7 +2,7 @@
日期 : @DATE@
瀏覽器 : @BROWSER@
-IP位址 : @IPADDRESS@
+IP 位址 : @IPADDRESS@
主機名稱 : @HOSTNAME@
舊版本 : @OLDPAGE@
新版本 : @NEWPAGE@
diff --git a/inc/lang/zh-tw/norev.txt b/inc/lang/zh-tw/norev.txt
index bd1c7a623..2a32ba6a8 100644
--- a/inc/lang/zh-tw/norev.txt
+++ b/inc/lang/zh-tw/norev.txt
@@ -1,3 +1,3 @@
====== 無此版本 ======
-該版本的文件不存在。請用 「舊版」按鈕檢視該文件所有舊版本清單。 \ No newline at end of file
+該版本的文件不存在。請用「舊版」按鈕檢視該文件所有舊版本清單。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/preview.txt b/inc/lang/zh-tw/preview.txt
index c68f94819..95d4b10e1 100644
--- a/inc/lang/zh-tw/preview.txt
+++ b/inc/lang/zh-tw/preview.txt
@@ -1,4 +1,4 @@
====== 預覽 ======
-以下是預覽該文件的狀態。請記住:**它還沒被儲存喔**!
+以下是該文件的預覽。請記住:**您還未儲存它**!
diff --git a/inc/lang/zh-tw/pwconfirm.txt b/inc/lang/zh-tw/pwconfirm.txt
index 994367980..fb8a5cb82 100644
--- a/inc/lang/zh-tw/pwconfirm.txt
+++ b/inc/lang/zh-tw/pwconfirm.txt
@@ -1,13 +1,13 @@
@FULLNAME@ 您好!
-有人為您在 @DOKUWIKIURL@ 註冊的使用者 @TITLE@ 請求新密碼
+感謝您在 @TITLE@ ( @DOKUWIKIURL@ ) 註冊了使用者帳號。我們收到請求,希望能允許此帳號使用新密碼。
-如果您沒有請求新密碼,請忽略這封郵件。
+如果您沒有發送此請求,請忽略這封郵件。
-要確認使用新密碼,請拜訪以下的連結。
+若您真的要使用新密碼,請拜訪以下的連結。
@CONFIRM@
--
本信件由以下 DokuWiki 站台產生:
-@DOKUWIKIURL@
+@DOKUWIKIURL@ \ No newline at end of file
diff --git a/inc/lang/zh-tw/read.txt b/inc/lang/zh-tw/read.txt
index a8305611f..4a472cd0d 100644
--- a/inc/lang/zh-tw/read.txt
+++ b/inc/lang/zh-tw/read.txt
@@ -1 +1 @@
-本頁是唯讀的,您可以看到原始碼,但不能更動它。您如果覺得這是誤判,請詢問管理員。 \ No newline at end of file
+本頁是唯讀的,您可以看到原始碼,但不能更動它。您如果覺得它不應被鎖上,請詢問管理員。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/register.txt b/inc/lang/zh-tw/register.txt
index 0da401ccd..3ff68dee3 100644
--- a/inc/lang/zh-tw/register.txt
+++ b/inc/lang/zh-tw/register.txt
@@ -1,4 +1,3 @@
====== 註冊新使用者 ======
-填寫以下資料以註冊維基帳號,請確定您提供的是**合法的 email 地址**-如果這裡沒要求您填寫密碼,您的新密碼會自動產生並寄送到該地址。登錄名稱必須是合法的[[doku>pagename|頁面名稱]]。
-
+若要註冊本 wiki 的帳號,請填寫下列資料。請確定您提供的是**合法的電郵地址**。如果您不必填寫密碼,系統就會為您自動產生登入密碼,並寄送到該電郵地址。登錄名稱須符合正確[[doku>pagename|頁面名稱]]之條件。
diff --git a/inc/lang/zh-tw/registermail.txt b/inc/lang/zh-tw/registermail.txt
index 489e3f9d3..fb4951d60 100644
--- a/inc/lang/zh-tw/registermail.txt
+++ b/inc/lang/zh-tw/registermail.txt
@@ -2,11 +2,11 @@
帳號 : @NEWUSER@
姓名 : @NEWNAME@
-E-mail : @NEWEMAIL@
+電郵 : @NEWEMAIL@
日期 : @DATE@
瀏覽器 : @BROWSER@
-IP位址 : @IPADDRESS@
+IP 位址 : @IPADDRESS@
主機名稱 : @HOSTNAME@
--
diff --git a/inc/lang/zh-tw/resendpwd.txt b/inc/lang/zh-tw/resendpwd.txt
index 3dbfad750..46078a348 100644
--- a/inc/lang/zh-tw/resendpwd.txt
+++ b/inc/lang/zh-tw/resendpwd.txt
@@ -1,3 +1,3 @@
====== 寄送新密碼 ======
-請在以下欄位輸入您的帳號,新密碼將會寄送到您註冊時填寫的 email 地址。
+請在以下欄位輸入您的帳號,新密碼將會寄送到您註冊時填寫的電郵地址。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/revisions.txt b/inc/lang/zh-tw/revisions.txt
index 479705b95..4818839ac 100644
--- a/inc/lang/zh-tw/revisions.txt
+++ b/inc/lang/zh-tw/revisions.txt
@@ -1,3 +1,3 @@
====== 舊版 ======
-以下是該文件的舊版本。如要恢復成某個舊版次,就點下它,然後按「編修本頁」,並存檔起來就可以了。
+以下是該文件的舊版本。如要恢復成某個舊版次,就點下它,然後按「編輯本頁」,並存檔起來就可以了。
diff --git a/inc/lang/zh-tw/stopwords.txt b/inc/lang/zh-tw/stopwords.txt
index 55b67ed16..e549250bd 100644
--- a/inc/lang/zh-tw/stopwords.txt
+++ b/inc/lang/zh-tw/stopwords.txt
@@ -1,9 +1,9 @@
-# 這檔是製作索引檔(index)時不要列入的關鍵字,格式為每字(詞)就使用一行。
-# 在修改時,請注意要用 UNIX 格式的換行符號(newline)處理,而非 DOS 的 CR-LR 喔
-# (如果在 MS Windows 環境使用的話,可使用 vim win32版 或 UltraEdit或其他類似編輯器修改)
+# 本清單列出製作索引檔 (index) 時不要列入的關鍵字,格式為每字 (詞) 佔一行。
+# 在修改本清單時,請注意要用 UNIX 格式的換行符號 (newline) 處理,而非 DOS 的 CR-LR 。
+# (如果在 MS Windows 環境使用的話,可使用 vim win32 版、 UltraEdit 或其他類似編輯器修改。)
#
-# 還有,不必把小於 3 個字元(英數字元)都包括進來。
-# 目前本清單的內容是以 http://www.ranks.nl/stopwords/ 為基礎而發展的。
+# 還有,不必把小於 3 個字元 (英數字元) 都包括進來。
+# 目前本清單的內容是以 http://www.ranks.nl/stopwords/ 為基礎,發展而成的。
about
are
and
diff --git a/inc/lang/zh-tw/subscr_digest.txt b/inc/lang/zh-tw/subscr_digest.txt
index a0f2be73e..a17a0551d 100644
--- a/inc/lang/zh-tw/subscr_digest.txt
+++ b/inc/lang/zh-tw/subscr_digest.txt
@@ -1,6 +1,6 @@
您好!
-維基 @TITLE@ 的頁面 @PAGE@ 已更改。
+本 wiki ( @TITLE@ ) 的頁面 @PAGE@ 已更改。
更改內容如下:
--------------------------------------------------------
@@ -10,9 +10,9 @@
舊版本:@OLDPAGE@
新版本:@NEWPAGE@
-要取消頁面提醒,請登入維基 @DOKUWIKIURL@
+要取消頁面提醒,請登入本 wiki @DOKUWIKIURL@
然後拜訪 @SUBSCRIBE@
-並取消訂閱頁面或分類空間的更改。
+並取消訂閱頁面或分類名稱的更改。
--
本信件由以下 DokuWiki 站台產生:
diff --git a/inc/lang/zh-tw/subscr_form.txt b/inc/lang/zh-tw/subscr_form.txt
index 394d4cbad..ba3f16113 100644
--- a/inc/lang/zh-tw/subscr_form.txt
+++ b/inc/lang/zh-tw/subscr_form.txt
@@ -1,3 +1,3 @@
====== 訂閱管理 ======
-這個頁面允許您管理在目前頁面和分類空間的訂閱。 \ No newline at end of file
+在此頁裏,您可以管理在目前頁面及分類名稱之訂閱。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/subscr_list.txt b/inc/lang/zh-tw/subscr_list.txt
index 078eae63e..ea82dd35d 100644
--- a/inc/lang/zh-tw/subscr_list.txt
+++ b/inc/lang/zh-tw/subscr_list.txt
@@ -1,15 +1,15 @@
您好!
-維基 @TITLE@ 的 @PAGE@ 分類空間的頁面已更改。
+本 wiki ( @TITLE@ ) 的 @PAGE@ 分類名稱頁面已更改。
更改內容如下:
--------------------------------------------------------
@DIFF@
--------------------------------------------------------
-要取消頁面提醒,請登入維基 @DOKUWIKIURL@
+要取消頁面提醒,請登入本 wiki @DOKUWIKIURL@
然後拜訪 @SUBSCRIBE@
-並取消訂閱頁面或分類空間的更改。
+並取消訂閱頁面或分類名稱的更改。
--
本信件由以下 DokuWiki 站台產生:
diff --git a/inc/lang/zh-tw/subscr_single.txt b/inc/lang/zh-tw/subscr_single.txt
index 5128140d0..14d87bb73 100644
--- a/inc/lang/zh-tw/subscr_single.txt
+++ b/inc/lang/zh-tw/subscr_single.txt
@@ -1,6 +1,6 @@
您好!
-維基 @TITLE@ 的頁面 @PAGE@ 已更改。
+本 wiki ( @TITLE@ ) 的頁面 @PAGE@ 已更改。
更改內容如下:
--------------------------------------------------------
@@ -13,9 +13,9 @@
舊版本 : @OLDPAGE@
新版本 : @NEWPAGE@
-要取消頁面提醒,請登入維基 @DOKUWIKIURL@
+要取消頁面提醒,請登入本 wiki @DOKUWIKIURL@
然後拜訪 @NEWPAGE@
-並取消訂閱頁面或分類空間的更改。
+並取消訂閱頁面或分類名稱的更改。
--
本信件由以下 DokuWiki 站台產生:
diff --git a/inc/lang/zh-tw/updateprofile.txt b/inc/lang/zh-tw/updateprofile.txt
index 47f2ae1c4..a7a2ad803 100644
--- a/inc/lang/zh-tw/updateprofile.txt
+++ b/inc/lang/zh-tw/updateprofile.txt
@@ -1,3 +1,3 @@
====== 更新個人資料 ======
-您只需變更想更新的欄位就好,帳號名稱不能變更。 \ No newline at end of file
+您只需修改想更新的欄位就好,帳號名稱不能變更。 \ No newline at end of file
diff --git a/inc/lang/zh-tw/uploadmail.txt b/inc/lang/zh-tw/uploadmail.txt
index b4c1311ba..87bac7c9a 100644
--- a/inc/lang/zh-tw/uploadmail.txt
+++ b/inc/lang/zh-tw/uploadmail.txt
@@ -3,7 +3,7 @@
檔名 : @MEDIA@
日期 : @DATE@
瀏覽器 : @BROWSER@
-IP位址 : @IPADDRESS@
+IP 位址 : @IPADDRESS@
主機名稱 : @HOSTNAME@
大小 : @SIZE@
MIME類型 : @MIME@
@@ -11,4 +11,4 @@ MIME類型 : @MIME@
--
本信件由以下 DokuWiki 站台產生:
-@DOKUWIKIURL@
+@DOKUWIKIURL@ \ No newline at end of file
diff --git a/inc/lang/zh/lang.php b/inc/lang/zh/lang.php
index b21a74ed5..e6e568cb5 100644
--- a/inc/lang/zh/lang.php
+++ b/inc/lang/zh/lang.php
@@ -289,8 +289,8 @@ $lang['i_writeerr'] = '无法创建 <code>%s</code>。您需要检查
$lang['i_badhash'] = '无法识别的或被修改的 dokuwiki.php(值=<code>%s</code>)';
$lang['i_badval'] = '<code>%s</code> - 非法或空值';
$lang['i_success'] = '配置成功完成。您现在可以删除 install.php 了。继续进入
- <a href="doku.php">您全新的 DokuWiki</a>。';
-$lang['i_failure'] = '写入配置文件的时候产生一些错误。在使用 <a href="doku.php">您全新安装的 DokuWiki</a> 前
+ <a href="doku.php?id=wiki:welcome">您全新的 DokuWiki</a>。';
+$lang['i_failure'] = '写入配置文件的时候产生一些错误。在使用 <a href="doku.php?id=wiki:welcome">您全新安装的 DokuWiki</a> 前
您需要手动修复它们。';
$lang['i_policy'] = '初始的 ACL 政策';
$lang['i_pol0'] = '开放的维基(任何人都有读、写、上传的权限)';
diff --git a/inc/load.php b/inc/load.php
index 008613b2a..5ca9b4cd8 100644
--- a/inc/load.php
+++ b/inc/load.php
@@ -70,6 +70,7 @@ function load_autoload($name){
'IXR_IntrospectionServer' => DOKU_INC.'inc/IXR_Library.php',
'Doku_Plugin_Controller'=> DOKU_INC.'inc/plugincontroller.class.php',
'GeSHi' => DOKU_INC.'inc/geshi.php',
+ 'Tar' => DOKU_INC.'inc/Tar.class.php',
'TarLib' => DOKU_INC.'inc/TarLib.class.php',
'ZipLib' => DOKU_INC.'inc/ZipLib.class.php',
'DokuWikiFeedCreator' => DOKU_INC.'inc/feedcreator.class.php',
@@ -80,6 +81,7 @@ function load_autoload($name){
'Mailer' => DOKU_INC.'inc/Mailer.class.php',
'RemoteAPI' => DOKU_INC.'inc/remote.php',
'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php',
+ 'Subscription' => DOKU_INC.'inc/subscription.php',
'DokuWiki_Action_Plugin' => DOKU_PLUGIN.'action.php',
'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php',
diff --git a/inc/media.php b/inc/media.php
index 6335bf210..572b1177c 100644
--- a/inc/media.php
+++ b/inc/media.php
@@ -535,32 +535,13 @@ function media_contentcheck($file,$mime){
* Send a notify mail on uploads
*
* @author Andreas Gohr <andi@splitbrain.org>
- * @fixme this should embed thumbnails of images in HTML version
*/
function media_notify($id,$file,$mime,$old_rev=false){
- global $lang;
global $conf;
- global $INFO;
if(empty($conf['notify'])) return; //notify enabled?
- $text = rawLocale('uploadmail');
- $trep = array(
- 'MIME' => $mime,
- 'MEDIA' => ml($id,'',true,'&',true),
- 'SIZE' => filesize_h(filesize($file)),
- );
-
- if ($old_rev && $conf['mediarevisions']) {
- $trep['OLD'] = ml($id, "rev=$old_rev", true, '&', true);
- } else {
- $trep['OLD'] = '---';
- }
-
- $mail = new Mailer();
- $mail->to($conf['notify']);
- $mail->subject($lang['mail_upload'].' '.$id);
- $mail->setBody($text,$trep);
- return $mail->send();
+ $subscription = new Subscription();
+ return $subscription->send_media_diff($conf['notify'], 'uploadmail', $id, $old_rev, '');
}
/**
diff --git a/inc/pageutils.php b/inc/pageutils.php
index 3bb10883f..ca4936a82 100644
--- a/inc/pageutils.php
+++ b/inc/pageutils.php
@@ -115,11 +115,10 @@ function cleanID($raw_id,$ascii=false,$media=false){
$id = utf8_strtolower($id);
//alternative namespace seperator
- $id = strtr($id,';',':');
if($conf['useslash']){
- $id = strtr($id,'/',':');
+ $id = strtr($id,';/','::');
}else{
- $id = strtr($id,'/',$sepchar);
+ $id = strtr($id,';/',':'.$sepchar);
}
if($conf['deaccent'] == 2 || $ascii) $id = utf8_romanize($id);
@@ -645,6 +644,7 @@ function utf8_decodeFN($file){
* @return string|false the full page id of the found page, false if any
*/
function page_findnearest($page){
+ if (!$page) return false;
global $ID;
$ns = $ID;
diff --git a/inc/parser/renderer.php b/inc/parser/renderer.php
index 2c78f220a..7df369478 100644
--- a/inc/parser/renderer.php
+++ b/inc/parser/renderer.php
@@ -274,9 +274,10 @@ class Doku_Renderer extends DokuWiki_Plugin {
list($name,$hash) = explode('#',$name,2);
if($hash) return $hash;
- $name = strtr($name,';',':');
if($conf['useslash']){
- $name = strtr($name,'/',':');
+ $name = strtr($name,';/',';:');
+ }else{
+ $name = strtr($name,';',':');
}
return noNSorNS($name);
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index b4e78a530..71f3aa4bf 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -30,6 +30,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
var $toc = array(); // will contain the Table of Contents
var $sectionedits = array(); // A stack of section edit data
+ private $lastsecid = 0; // last section edit id, used by startSectionEdit
var $headers = array();
var $footnotes = array();
@@ -50,9 +51,8 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
* @author Adrian Lang <lang@cosmocode.de>
*/
public function startSectionEdit($start, $type, $title = null) {
- static $lastsecid = 0;
- $this->sectionedits[] = array(++$lastsecid, $start, $type, $title);
- return 'sectionedit' . $lastsecid;
+ $this->sectionedits[] = array(++$this->lastsecid, $start, $type, $title);
+ return 'sectionedit' . $this->lastsecid;
}
/**
@@ -803,6 +803,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
$link['class'] .= ' mediafile mf_'.$class;
$link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true);
+ $link['title'] .= ' (' . filesize_h(filesize(mediaFN($src))).')';
}
if($hash) $link['url'] .= '#'.$hash;
diff --git a/inc/plugin.php b/inc/plugin.php
index 6ffc1ddcb..cd6bd5ac7 100644
--- a/inc/plugin.php
+++ b/inc/plugin.php
@@ -82,8 +82,8 @@ class DokuWiki_Plugin {
* retrieve a language dependent file and pass to xhtml renderer for display
* plugin equivalent of p_locale_xhtml()
*
- * @param $id id of language dependent wiki page
- * @return string parsed contents of the wiki page in xhtml format
+ * @param string $id id of language dependent wiki page
+ * @return string parsed contents of the wiki page in xhtml format
*/
function locale_xhtml($id) {
return p_cached_output($this->localFN($id));
@@ -193,12 +193,12 @@ class DokuWiki_Plugin {
*
* @author Esther Brunner <wikidesign@gmail.com>
*
- * @param $name name of plugin to load
- * @param $msg message to display in case the plugin is not available
+ * @param string $name name of plugin to load
+ * @param bool $msg if a message should be displayed in case the plugin is not available
*
* @return object helper plugin object
*/
- function loadHelper($name, $msg){
+ function loadHelper($name, $msg = true){
if (!plugin_isdisabled($name)){
$obj = plugin_load('helper',$name);
}else{
diff --git a/inc/search.php b/inc/search.php
index 1cecfd5ec..cc3e79006 100644
--- a/inc/search.php
+++ b/inc/search.php
@@ -16,12 +16,13 @@ if(!defined('DOKU_INC')) die('meh.');
*
* @param array ref $data The results of the search are stored here
* @param string $base Where to start the search
- * @param callback $func Callback (function name or arayy with object,method)
+ * @param callback $func Callback (function name or array with object,method)
* @param string $dir Current directory beyond $base
* @param int $lvl Recursion Level
+ * @param mixed $sort 'natural' to use natural order sorting (default); 'date' to sort by filemtime; leave empty to skip sorting.
* @author Andreas Gohr <andi@splitbrain.org>
*/
-function search(&$data,$base,$func,$opts,$dir='',$lvl=1,$sort=false){
+function search(&$data,$base,$func,$opts,$dir='',$lvl=1,$sort='natural'){
$dirs = array();
$files = array();
$filepaths = array();
@@ -39,17 +40,19 @@ function search(&$data,$base,$func,$opts,$dir='',$lvl=1,$sort=false){
$filepaths[] = $base.'/'.$dir.'/'.$file;
}
closedir($dh);
- if ($sort == 'date') {
- @array_multisort(array_map('filemtime', $filepaths), SORT_NUMERIC, SORT_DESC, $files);
- } else {
- sort($files);
+ if (!empty($sort)) {
+ if ($sort == 'date') {
+ @array_multisort(array_map('filemtime', $filepaths), SORT_NUMERIC, SORT_DESC, $files);
+ } else /* natural */ {
+ natsort($files);
+ }
+ natsort($dirs);
}
- sort($dirs);
//give directories to userfunction then recurse
foreach($dirs as $dir){
if (call_user_func_array($func, array(&$data,$base,$dir,'d',$lvl,$opts))){
- search($data,$base,$func,$opts,$dir,$lvl+1);
+ search($data,$base,$func,$opts,$dir,$lvl+1,$sort);
}
}
//now handle the files
@@ -247,11 +250,16 @@ function search_pagename(&$data,$base,$file,$type,$lvl,$opts){
* @author Andreas Gohr <andi@splitbrain.org>
*/
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)){
+ return false; // depth reached
+ }
+ }
+
//we do nothing with directories
if($type == 'd'){
- if(!$opts['depth']) return true; // recurse forever
- $parts = explode('/',ltrim($file,'/'));
- if(count($parts) == $opts['depth']) return false; // depth reached
return true;
}
diff --git a/inc/subscription.php b/inc/subscription.php
index 6b201c266..2989de032 100644
--- a/inc/subscription.php
+++ b/inc/subscription.php
@@ -1,414 +1,697 @@
<?php
/**
- * Utilities for handling (email) subscriptions
- *
- * The public interface of this file consists of the functions
- * - subscription_find
- * - subscription_send_digest
- * - subscription_send_list
- * - subscription_set
- * - get_info_subscribed
- * - subscription_addresslist
- * - subscription_lock
- * - subscription_unlock
+ * Class for handling (email) subscriptions
*
* @author Adrian Lang <lang@cosmocode.de>
+ * @author Andreas Gohr <andi@splitbrain.org>
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
+class Subscription {
-/**
- * Get the name of the metafile tracking subscriptions to target page or
- * namespace
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $id The target page or namespace, specified by id; Namespaces
- * are identified by appending a colon.
- * @return string
- */
-function subscription_filename($id) {
- $meta_fname = '.mlist';
- if ((substr($id, -1, 1) === ':')) {
- $meta_froot = getNS($id);
- $meta_fname = '/' . $meta_fname;
- } else {
- $meta_froot = $id;
+ /**
+ * Check if subscription system is enabled
+ *
+ * @return bool
+ */
+ public function isenabled() {
+ return actionOK('subscribe');
}
- return metaFN((string) $meta_froot, $meta_fname);
-}
-/**
- * Lock subscription info for an ID
- *
- * @author Adrian Lang <lang@cosmocode.de>
- * @param string $id The target page or namespace, specified by id; Namespaces
- * are identified by appending a colon.
- * @return string
- */
-function subscription_lock_filename ($id){
- global $conf;
- return $conf['lockdir'].'/_subscr_' . md5($id) . '.lock';
-}
+ /**
+ * Return the subscription meta file for the given ID
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ * @return string
+ */
+ protected function file($id) {
+ $meta_fname = '.mlist';
+ if((substr($id, -1, 1) === ':')) {
+ $meta_froot = getNS($id);
+ $meta_fname = '/'.$meta_fname;
+ } else {
+ $meta_froot = $id;
+ }
+ return metaFN((string) $meta_froot, $meta_fname);
+ }
-/**
- * Creates a lock file for writing subscription data
- *
- * @todo add lock time parameter to io_lock() and use this instead
- * @param $id
- * @return bool
- */
-function subscription_lock($id) {
- global $conf;
- $lock = subscription_lock_filename($id);
+ /**
+ * Lock subscription info
+ *
+ * We don't use io_lock() her because we do not wait for the lock and use a larger stale time
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ * @return bool true, if you got a succesful lock
+ */
+ protected function lock($id) {
+ global $conf;
+
+ $lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock';
+
+ if(is_dir($lock) && time() - @filemtime($lock) > 60 * 5) {
+ // looks like a stale lock - remove it
+ @rmdir($lock);
+ }
+
+ // try creating the lock directory
+ if(!@mkdir($lock, $conf['dmode'])) {
+ return false;
+ }
- if (is_dir($lock) && time()-@filemtime($lock) > 60*5) {
- // looks like a stale lock - remove it
- @rmdir($lock);
+ if($conf['dperm']) chmod($lock, $conf['dperm']);
+ return true;
}
- // try creating the lock directory
- if (!@mkdir($lock,$conf['dmode'])) {
- return false;
+ /**
+ * Unlock subscription info
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ * @return bool
+ */
+ protected function unlock($id) {
+ global $conf;
+ $lock = $conf['lockdir'].'/_subscr_'.md5($id).'.lock';
+ return @rmdir($lock);
}
- if($conf['dperm']) chmod($lock, $conf['dperm']);
- return true;
-}
+ /**
+ * Construct a regular expression for parsing a subscription definition line
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ * @return string complete regexp including delimiters
+ * @throws Exception when no data is passed
+ */
+ protected function buildregex($user = null, $style = null, $data = null) {
+ // always work with arrays
+ $user = (array) $user;
+ $style = (array) $style;
+ $data = (array) $data;
-/**
- * Unlock subscription info for an ID
- *
- * @author Adrian Lang <lang@cosmocode.de>
- * @param string $id The target page or namespace, specified by id; Namespaces
- * are identified by appending a colon.
- * @return bool
- */
-function subscription_unlock($id) {
- $lockf = subscription_lock_filename($id);
- return @rmdir($lockf);
-}
+ // clean
+ $user = array_filter(array_map('trim', $user));
+ $style = array_filter(array_map('trim', $style));
+ $data = array_filter(array_map('trim', $data));
-/**
- * Set subscription information
- *
- * Allows to set subscription information for permanent storage in meta files.
- * Subscriptions consist of a target object, a subscribing user, a subscribe
- * style and optional data.
- * A subscription may be deleted by specifying an empty subscribe style.
- * Only one subscription per target and user is allowed.
- * The function returns false on error, otherwise true. Note that no error is
- * returned if a subscription should be deleted but the user is not subscribed
- * and the subscription meta file exists.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $user The subscriber or unsubscriber
- * @param string $page The target object (page or namespace), specified by
- * id; Namespaces are identified by a trailing colon.
- * @param string $style The subscribe style; DokuWiki currently implements
- * “every”, “digest”, and “list”.
- * @param string $data An optional data blob
- * @param bool $overwrite Whether an existing subscription may be overwritten
- * @return bool
- */
-function subscription_set($user, $page, $style, $data = null,
- $overwrite = false) {
- global $lang;
- if (is_null($style)) {
- // Delete subscription.
- $file = subscription_filename($page);
- if (!@file_exists($file)) {
- msg(sprintf($lang['subscr_not_subscribed'], $user,
- prettyprint_id($page)), -1);
- return false;
+ // user names are encoded
+ $user = array_map('auth_nameencode', $user);
+
+ // quote
+ $user = array_map('preg_quote_cb', $user);
+ $style = array_map('preg_quote_cb', $style);
+ $data = array_map('preg_quote_cb', $data);
+
+ // join
+ $user = join('|', $user);
+ $style = join('|', $style);
+ $data = join('|', $data);
+
+ // any data at all?
+ if($user.$style.$data === '') throw new Exception('no data passed');
+
+ // replace empty values, set which ones are optional
+ $sopt = '';
+ $dopt = '';
+ if($user === '') {
+ $user = '\S+';
+ }
+ if($style === '') {
+ $style = '\S+';
+ $sopt = '?';
+ }
+ if($data === '') {
+ $data = '\S+';
+ $dopt = '?';
}
- // io_deleteFromFile does not return false if no line matched.
- return io_deleteFromFile($file,
- subscription_regex(array('user' => auth_nameencode($user))),
- true);
+ // assemble
+ return "/^($user)(?:\\s+($style))$sopt(?:\\s+($data))$dopt$/";
}
- // Delete subscription if one exists and $overwrite is true. If $overwrite
- // is false, fail.
- $subs = subscription_find($page, array('user' => $user));
- if (count($subs) > 0 && isset($subs[$page])) {
- if (!$overwrite) {
- msg(sprintf($lang['subscr_already_subscribed'], $user,
- prettyprint_id($page)), -1);
- return false;
- }
- // Fail if deletion failed, else continue.
- if (!subscription_set($user, $page, null)) {
- return false;
+ /**
+ * Recursively search for matching subscriptions
+ *
+ * This function searches all relevant subscription files for a page or
+ * namespace.
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $page The target object’s (namespace or page) id
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ * @return array
+ */
+ public function subscribers($page, $user = null, $style = null, $data = null) {
+ if(!$this->isenabled()) return array();
+
+ // Construct list of files which may contain relevant subscriptions.
+ $files = array(':' => $this->file(':'));
+ do {
+ $files[$page] = $this->file($page);
+ $page = getNS(rtrim($page, ':')).':';
+ } while($page !== ':');
+
+ $re = $this->buildregex($user, $style, $data);
+
+ // Handle files.
+ $result = array();
+ foreach($files as $target => $file) {
+ if(!@file_exists($file)) continue;
+
+ $lines = file($file);
+ foreach($lines as $line) {
+ // fix old style subscription files
+ if(strpos($line, ' ') === false) $line = trim($line)." every\n";
+
+ // check for matching entries
+ if(!preg_match($re, $line, $m)) continue;
+
+ $u = rawurldecode($m[1]); // decode the user name
+ if(!isset($result[$target])) $result[$target] = array();
+ $result[$target][$u] = array($m[2], $m[3]); // add to result
+ }
}
+ return array_reverse($result);
}
- $file = subscription_filename($page);
- $content = auth_nameencode($user) . ' ' . $style;
- if (!is_null($data)) {
- $content .= ' ' . $data;
+ /**
+ * Adds a new subscription for the given page or namespace
+ *
+ * This will automatically overwrite any existent subscription for the given user on this
+ * *exact* page or namespace. It will *not* modify any subscription that may exist in higher namespaces.
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ * @param string $user
+ * @param string $style
+ * @param string $data
+ * @throws Exception when user or style is empty
+ * @return bool
+ */
+ public function add($id, $user, $style, $data = '') {
+ if(!$this->isenabled()) return false;
+
+ // delete any existing subscription
+ $this->remove($id, $user);
+
+ $user = auth_nameencode(trim($user));
+ $style = trim($style);
+ $data = trim($data);
+
+ if(!$user) throw new Exception('no subscription user given');
+ if(!$style) throw new Exception('no subscription style given');
+ if(!$data) $data = time(); //always add current time for new subscriptions
+
+ $line = "$user $style $data\n";
+ $file = $this->file($id);
+ return io_saveFile($file, $line, true);
}
- return io_saveFile($file, $content . "\n", true);
-}
-/**
- * Recursively search for matching subscriptions
- *
- * This function searches all relevant subscription files for a page or
- * namespace.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- * @see function subscription_regex for $pre documentation
- *
- * @param string $page The target object’s (namespace or page) id
- * @param array $pre A hash of predefined values
- * @return array
- */
-function subscription_find($page, $pre) {
- // Construct list of files which may contain relevant subscriptions.
- $filenames = array(':' => subscription_filename(':'));
- do {
- $filenames[$page] = subscription_filename($page);
- $page = getNS(rtrim($page, ':')) . ':';
- } while ($page !== ':');
-
- // Handle files.
- $matches = array();
- foreach ($filenames as $cur_page => $filename) {
- if (!@file_exists($filename)) {
- continue;
+ /**
+ * Removes a subscription for the given page or namespace
+ *
+ * This removes all subscriptions matching the given criteria on the given page or
+ * namespace. It will *not* modify any subscriptions that may exist in higher
+ * namespaces.
+ *
+ * @param string $id The target object’s (namespace or page) id
+ * @param string|array $user
+ * @param string|array $style
+ * @param string|array $data
+ * @return bool
+ */
+ public function remove($id, $user = null, $style = null, $data = null) {
+ if(!$this->isenabled()) return false;
+
+ $file = $this->file($id);
+ if(!file_exists($file)) return true;
+
+ $re = $this->buildregex($user, $style, $data);
+ return io_deleteFromFile($file, $re, true);
+ }
+
+ /**
+ * Get data for $INFO['subscribed']
+ *
+ * $INFO['subscribed'] is either false if no subscription for the current page
+ * and user is in effect. Else it contains an array of arrays with the fields
+ * “target”, “style”, and optionally “data”.
+ *
+ * @param string $id Page ID, defaults to global $ID
+ * @param string $user User, defaults to $_SERVER['REMOTE_USER']
+ * @return array
+ * @author Adrian Lang <lang@cosmocode.de>
+ */
+ function user_subscription($id = '', $user = '') {
+ if(!$this->isenabled()) return false;
+
+ global $ID;
+ if(!$id) $id = $ID;
+ if(!$user) $user = $_SERVER['REMOTE_USER'];
+
+ $subs = $this->subscribers($id, $user);
+ if(!count($subs)) return false;
+
+ $result = array();
+ foreach($subs as $target => $info) {
+ $result[] = array(
+ 'target' => $target,
+ 'style' => $info[$user][0],
+ 'data' => $info[$user][1]
+ );
}
- $subscriptions = file($filename);
- foreach ($subscriptions as $subscription) {
- if (strpos($subscription, ' ') === false) {
- // This is an old subscription file.
- $subscription = trim($subscription) . " every\n";
- }
- list($user, $rest) = explode(' ', $subscription, 2);
- $subscription = rawurldecode($user) . " " . $rest;
+ return $result;
+ }
- if (preg_match(subscription_regex($pre), $subscription,
- $line_matches) === 0) {
- continue;
- }
- $match = array_slice($line_matches, 1);
- if (!isset($matches[$cur_page])) {
- $matches[$cur_page] = array();
+ /**
+ * Send digest and list subscriptions
+ *
+ * This sends mails to all subscribers that have a subscription for namespaces above
+ * the given page if the needed $conf['subscribe_time'] has passed already.
+ *
+ * This function is called form lib/exe/indexer.php
+ *
+ * @param string $page
+ * @return int number of sent mails
+ */
+ public function send_bulk($page) {
+ if(!$this->isenabled()) return 0;
+
+ /** @var auth_basic $auth */
+ global $auth;
+ global $conf;
+ global $USERINFO;
+ $count = 0;
+
+ $subscriptions = $this->subscribers($page, null, array('digest', 'list'));
+
+ // remember current user info
+ $olduinfo = $USERINFO;
+ $olduser = $_SERVER['REMOTE_USER'];
+
+ foreach($subscriptions as $target => $users) {
+ if(!$this->lock($target)) continue;
+
+ foreach($users as $user => $info) {
+ list($style, $lastupdate) = $info;
+
+ $lastupdate = (int) $lastupdate;
+ if($lastupdate + $conf['subscribe_time'] > time()) {
+ // Less than the configured time period passed since last
+ // update.
+ continue;
+ }
+
+ // Work as the user to make sure ACLs apply correctly
+ $USERINFO = $auth->getUserData($user);
+ $_SERVER['REMOTE_USER'] = $user;
+ if($USERINFO === false) continue;
+ if(!$USERINFO['mail']) continue;
+
+ if(substr($target, -1, 1) === ':') {
+ // subscription target is a namespace, get all changes within
+ $changes = getRecentsSince($lastupdate, null, getNS($target));
+ } else {
+ // single page subscription, check ACL ourselves
+ if(auth_quickaclcheck($target) < AUTH_READ) continue;
+ $meta = p_get_metadata($target);
+ $changes = array($meta['last_change']);
+ }
+
+ // Filter out pages only changed in small and own edits
+ $change_ids = array();
+ foreach($changes as $rev) {
+ $n = 0;
+ while(!is_null($rev) && $rev['date'] >= $lastupdate &&
+ ($_SERVER['REMOTE_USER'] === $rev['user'] ||
+ $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
+ $rev = getRevisions($rev['id'], $n++, 1);
+ $rev = (count($rev) > 0) ? $rev[0] : null;
+ }
+
+ if(!is_null($rev) && $rev['date'] >= $lastupdate) {
+ // Some change was not a minor one and not by myself
+ $change_ids[] = $rev['id'];
+ }
+ }
+
+ // send it
+ if($style === 'digest') {
+ foreach($change_ids as $change_id) {
+ $this->send_digest(
+ $USERINFO['mail'], $change_id,
+ $lastupdate
+ );
+ $count++;
+ }
+ } elseif($style === 'list') {
+ $this->send_list($USERINFO['mail'], $change_ids, $target);
+ $count++;
+ }
+ // TODO: Handle duplicate subscriptions.
+
+ // Update notification time.
+ $this->add($target, $user, $style, time());
}
- $matches[$cur_page][] = $match;
+ $this->unlock($target);
}
- }
- return array_reverse($matches);
-}
-/**
- * Get data for $INFO['subscribed']
- *
- * $INFO['subscribed'] is either false if no subscription for the current page
- * and user is in effect. Else it contains an array of arrays with the fields
- * “target”, “style”, and optionally “data”.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- */
-function get_info_subscribed() {
- global $ID;
- global $conf;
- if (!$conf['subscribers']) {
- return false;
+ // restore current user info
+ $USERINFO = $olduinfo;
+ $_SERVER['REMOTE_USER'] = $olduser;
+ return $count;
}
- $subs = subscription_find($ID, array('user' => $_SERVER['REMOTE_USER']));
- if (count($subs) === 0) {
- return false;
+ /**
+ * Send the diff for some page change
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $template Mail template ('subscr_digest', 'subscr_single', 'mailtext', ...)
+ * @param string $id Page for which the notification is
+ * @param int|null $rev Old revision if any
+ * @param string $summary Change summary if any
+ * @return bool true if successfully sent
+ */
+ public function send_diff($subscriber_mail, $template, $id, $rev = null, $summary = '') {
+ global $DIFF_INLINESTYLES;
+
+ // prepare replacements (keys not set in hrep will be taken from trep)
+ $trep = array(
+ 'PAGE' => $id,
+ 'NEWPAGE' => wl($id, '', true, '&'),
+ 'SUMMARY' => $summary,
+ 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&')
+ );
+ $hrep = array();
+
+ if($rev) {
+ $subject = 'changed';
+ $trep['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
+
+ $old_content = rawWiki($id, $rev);
+ $new_content = rawWiki($id);
+
+ $df = new Diff(explode("\n", $old_content),
+ explode("\n", $new_content));
+ $dformat = new UnifiedDiffFormatter();
+ $tdiff = $dformat->format($df);
+
+ $DIFF_INLINESTYLES = true;
+ $df = new Diff(explode("\n", hsc($old_content)),
+ explode("\n", hsc($new_content)));
+ $dformat = new InlineDiffFormatter();
+ $hdiff = $dformat->format($df);
+ $hdiff = '<table>'.$hdiff.'</table>';
+ $DIFF_INLINESTYLES = false;
+ } else {
+ $subject = 'newpage';
+ $trep['OLDPAGE'] = '---';
+ $tdiff = rawWiki($id);
+ $hdiff = nl2br(hsc($tdiff));
+ }
+
+ $trep['DIFF'] = $tdiff;
+ $hrep['DIFF'] = $hdiff;
+
+ $headers = array('Message-Id' => $this->getMessageID($id));
+ if ($rev) {
+ $headers['In-Reply-To'] = $this->getMessageID($id, $rev);
+ }
+
+ return $this->send(
+ $subscriber_mail, $subject, $id,
+ $template, $trep, $hrep, $headers
+ );
}
- $_ret = array();
- foreach ($subs as $target => $subs_data) {
- $new = array('target' => $target,
- 'style' => $subs_data[0][0]);
- if (count($subs_data[0]) > 1) {
- $new['data'] = $subs_data[0][1];
+ /**
+ * Send the diff for some media change
+ *
+ * @fixme this should embed thumbnails of images in HTML version
+ * @param string $subscriber_mail The target mail address
+ * @param string $template Mail template ('uploadmail', ...)
+ * @param string $id Media file for which the notification is
+ * @param int|bool $rev Old revision if any
+ * @return bool true if successfully sent
+ */
+ public function send_media_diff($subscriber_mail, $template, $id, $rev = false) {
+ global $conf;
+
+ $file = mediaFN($id);
+ list($mime, $ext) = mimetype($id);
+
+ $trep = array(
+ 'MIME' => $mime,
+ 'MEDIA' => ml($id,'',true,'&',true),
+ 'SIZE' => filesize_h(filesize($file)),
+ );
+
+ if ($rev && $conf['mediarevisions']) {
+ $trep['OLD'] = ml($id, "rev=$rev", true, '&', true);
+ } else {
+ $trep['OLD'] = '---';
+ }
+
+ $headers = array('Message-Id' => $this->getMessageID($id, @filemtime($file)));
+ if ($rev) {
+ $headers['In-Reply-To'] = $this->getMessageID($id, $rev);
}
- $_ret[] = $new;
+
+ $this->send($subscriber_mail, 'upload', $id, $template, $trep, null, $headers);
+
}
- return $_ret;
-}
+ /**
+ * Send a notify mail on new registration
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $login login name of the new user
+ * @param string $fullname full name of the new user
+ * @param string $email email address of the new user
+ * @return bool true if a mail was sent
+ */
+ public function send_register($login, $fullname, $email) {
+ global $conf;
+ if(empty($conf['registernotify'])) return false;
-/**
- * Construct a regular expression parsing a subscription definition line
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param array $pre A hash of predefined values; “user”, “style”, and
- * “data” may be set to limit the results to
- * subscriptions matching these parameters. If
- * “escaped” is true, these fields are inserted into the
- * regular expression without escaping.
- *
- * @return string complete regexp including delimiters
- */
-function subscription_regex($pre = array()) {
- if (!isset($pre['escaped']) || $pre['escaped'] === false) {
- $pre = array_map('preg_quote_cb', $pre);
+ $trep = array(
+ 'NEWUSER' => $login,
+ 'NEWNAME' => $fullname,
+ 'NEWEMAIL' => $email,
+ );
+
+ return $this->send(
+ $conf['registernotify'],
+ 'new_user',
+ $login,
+ 'registermail',
+ $trep
+ );
}
- foreach (array('user', 'style', 'data') as $key) {
- if (!isset($pre[$key])) {
- $pre[$key] = '(\S+)';
+
+ /**
+ * Send a digest mail
+ *
+ * Sends a digest mail showing a bunch of changes of a single page. Basically the same as send_diff()
+ * but determines the last known revision first
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param array $id The ID
+ * @param int $lastupdate Time of the last notification
+ * @return bool
+ */
+ protected function send_digest($subscriber_mail, $id, $lastupdate) {
+ $n = 0;
+ do {
+ $rev = getRevisions($id, $n++, 1);
+ $rev = (count($rev) > 0) ? $rev[0] : null;
+ } while(!is_null($rev) && $rev > $lastupdate);
+
+ return $this->send_diff(
+ $subscriber_mail,
+ 'subscr_digest',
+ $id, $rev
+ );
+ }
+
+ /**
+ * Send a list mail
+ *
+ * Sends a list mail showing a list of changed pages.
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param array $ids Array of ids
+ * @param string $ns_id The id of the namespace
+ * @return bool true if a mail was sent
+ */
+ protected function send_list($subscriber_mail, $ids, $ns_id) {
+ if(count($ids) === 0) return false;
+
+ $tlist = '';
+ $hlist = '<ul>';
+ foreach($ids as $id) {
+ $link = wl($id, array(), true);
+ $tlist .= '* '.$link.NL;
+ $hlist .= '<li><a href="'.$link.'">'.hsc($id).'</a></li>'.NL;
}
+ $hlist .= '</ul>';
+
+ $id = prettyprint_id($ns_id);
+ $trep = array(
+ 'DIFF' => rtrim($tlist),
+ 'PAGE' => $id,
+ 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&')
+ );
+ $hrep = array(
+ 'DIFF' => $hlist
+ );
+
+ return $this->send(
+ $subscriber_mail,
+ 'subscribe_list',
+ $ns_id,
+ 'subscr_list', $trep, $hrep
+ );
}
- return '/^' . $pre['user'] . '(?: ' . $pre['style'] .
- '(?: ' . $pre['data'] . ')?)?$/';
-}
-/**
- * Return a string with the email addresses of all the
- * users subscribed to a page
- *
- * This is the default action for COMMON_NOTIFY_ADDRESSLIST.
- *
- * @author Steven Danz <steven-danz@kc.rr.com>
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @todo this does NOT return a string but uses a reference to write back, either fix function or docs
- * @param array $data Containing $id (the page id), $self (whether the author
- * should be notified, $addresslist (current email address
- * list)
- * @return string
- */
-function subscription_addresslist(&$data){
- global $conf;
- /** @var auth_basic $auth */
- global $auth;
+ /**
+ * Helper function for sending a mail
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $subject The lang id of the mail subject (without the
+ * prefix “mail_”)
+ * @param string $context The context of this mail, eg. page or namespace id
+ * @param string $template The name of the mail template
+ * @param array $trep Predefined parameters used to parse the
+ * template (in text format)
+ * @param array $hrep Predefined parameters used to parse the
+ * template (in HTML format), null to default to $trep
+ * @param array $headers Additional mail headers in the form 'name' => 'value'
+ * @return bool
+ */
+ protected function send($subscriber_mail, $subject, $context, $template, $trep, $hrep = null, $headers = array()) {
+ global $lang;
+ global $conf;
+
+ $text = rawLocale($template);
+ $subject = $lang['mail_'.$subject].' '.$context;
+ $mail = new Mailer();
+ $mail->bcc($subscriber_mail);
+ $mail->subject($subject);
+ $mail->setBody($text, $trep, $hrep);
+ if(in_array($template, array('subscr_list', 'subscr_digest'))){
+ $mail->from($conf['mailfromnobody']);
+ }
+ if(isset($trep['SUBSCRIBE'])) {
+ $mail->setHeader('List-Unsubscribe', '<'.$trep['SUBSCRIBE'].'>', false);
+ }
- $id = $data['id'];
- $self = $data['self'];
- $addresslist = $data['addresslist'];
+ foreach ($headers as $header => $value) {
+ $mail->setHeader($header, $value);
+ }
- if (!$conf['subscribers'] || $auth === null) {
- return '';
+ return $mail->send();
}
- $pres = array('style' => 'every', 'escaped' => true);
- if (!$self && isset($_SERVER['REMOTE_USER'])) {
- $pres['user'] = '((?!' . preg_quote_cb($_SERVER['REMOTE_USER']) .
- '(?: |$))\S+)';
+
+ /**
+ * Get a valid message id for a certain $id and revision (or the current revision)
+ * @param string $id The id of the page (or media file) the message id should be for
+ * @param string $rev The revision of the page, set to the current revision of the page $id if not set
+ * @return string
+ */
+ protected function getMessageID($id, $rev = NULL) {
+ static $listid = null;
+ if (is_null($listid)) {
+ $server = parse_url(DOKU_URL, PHP_URL_HOST);
+ $listid = join('.', array_reverse(explode('/', DOKU_BASE))).$server;
+ $listid = urlencode($listid);
+ $listid = strtolower(trim($listid, '.'));
+ }
+
+ if (is_null($rev)) {
+ $rev = @filemtime(wikiFN($id));
+ }
+
+ return "<$id?rev=$rev@$listid>";
}
- $subs = subscription_find($id, $pres);
- $emails = array();
- foreach ($subs as $by_targets) {
- foreach ($by_targets as $sub) {
- $info = $auth->getUserData($sub[0]);
- if ($info === false) continue;
- $level = auth_aclcheck($id, $sub[0], $info['grps']);
- if ($level >= AUTH_READ) {
- if (strcasecmp($info['mail'], $conf['notify']) != 0) {
- $emails[$sub[0]] = $info['mail'];
+
+ /**
+ * Default callback for COMMON_NOTIFY_ADDRESSLIST
+ *
+ * Aggregates all email addresses of user who have subscribed the given page with 'every' style
+ *
+ * @author Steven Danz <steven-danz@kc.rr.com>
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ * @todo move the whole functionality into this class, trigger SUBSCRIPTION_NOTIFY_ADDRESSLIST instead,
+ * use an array for the addresses within it
+ *
+ * @param array &$data Containing $id (the page id), $self (whether the author
+ * should be notified, $addresslist (current email address
+ * list)
+ */
+ public function notifyaddresses(&$data) {
+ if(!$this->isenabled()) return;
+
+ /** @var auth_basic $auth */
+ global $auth;
+ global $conf;
+
+ $id = $data['id'];
+ $self = $data['self'];
+ $addresslist = $data['addresslist'];
+
+ $subscriptions = $this->subscribers($id, null, 'every');
+
+ $result = array();
+ foreach($subscriptions as $target => $users) {
+ foreach($users as $user => $info) {
+ $userinfo = $auth->getUserData($user);
+ if($userinfo === false) continue;
+ if(!$userinfo['mail']) continue;
+ if(!$self && $user == $_SERVER['REMOTE_USER']) continue; //skip our own changes
+
+ $level = auth_aclcheck($id, $user, $userinfo['grps']);
+ if($level >= AUTH_READ) {
+ if(strcasecmp($userinfo['mail'], $conf['notify']) != 0) { //skip user who get notified elsewhere
+ $result[$user] = $userinfo['mail'];
+ }
}
}
}
+ $data['addresslist'] = trim($addresslist.','.implode(',', $result), ',');
}
- $data['addresslist'] = trim($addresslist . ',' . implode(',', $emails), ',');
}
/**
- * Send a digest mail
+ * Compatibility wrapper around Subscription:notifyaddresses
*
- * Sends a digest mail showing a bunch of changes.
+ * for plugins emitting COMMON_NOTIFY_ADDRESSLIST themselves and relying on on this to
+ * be the default handler
*
- * @author Adrian Lang <lang@cosmocode.de>
+ * @param array $data event data for
*
- * @param string $subscriber_mail The target mail address
- * @param array $id The ID
- * @param int $lastupdate Time of the last notification
+ * @deprecated 2012-12-07
*/
-function subscription_send_digest($subscriber_mail, $id, $lastupdate) {
- $n = 0;
- do {
- $rev = getRevisions($id, $n++, 1);
- $rev = (count($rev) > 0) ? $rev[0] : null;
- } while (!is_null($rev) && $rev > $lastupdate);
-
- $replaces = array('NEWPAGE' => wl($id, '', true, '&'),
- 'SUBSCRIBE' => wl($id, array('do' => 'subscribe'), true, '&'));
- if (!is_null($rev)) {
- $subject = 'changed';
- $replaces['OLDPAGE'] = wl($id, "rev=$rev", true, '&');
- $df = new Diff(explode("\n", rawWiki($id, $rev)),
- explode("\n", rawWiki($id)));
- $dformat = new UnifiedDiffFormatter();
- $replaces['DIFF'] = $dformat->format($df);
- } else {
- $subject = 'newpage';
- $replaces['OLDPAGE'] = 'none';
- $replaces['DIFF'] = rawWiki($id);
- }
- subscription_send($subscriber_mail, $replaces, $subject, $id,
- 'subscr_digest');
-}
-
-/**
- * Send a list mail
- *
- * Sends a list mail showing a list of changed pages.
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $subscriber_mail The target mail address
- * @param array $ids Array of ids
- * @param string $ns_id The id of the namespace
- */
-function subscription_send_list($subscriber_mail, $ids, $ns_id) {
- if (count($ids) === 0) return;
- global $conf;
- $list = '';
- foreach ($ids as $id) {
- $list .= '* ' . wl($id, array(), true) . NL;
- }
- subscription_send($subscriber_mail,
- array('DIFF' => rtrim($list),
- 'SUBSCRIBE' => wl($ns_id . $conf['start'],
- array('do' => 'subscribe'),
- true, '&')),
- 'subscribe_list',
- prettyprint_id($ns_id),
- 'subscr_list');
-}
-
-/**
- * Helper function for sending a mail
- *
- * @author Adrian Lang <lang@cosmocode.de>
- *
- * @param string $subscriber_mail The target mail address
- * @param array $replaces Predefined parameters used to parse the
- * template
- * @param string $subject The lang id of the mail subject (without the
- * prefix “mail_”)
- * @param string $id The page or namespace id
- * @param string $template The name of the mail template
- * @return bool
- */
-function subscription_send($subscriber_mail, $replaces, $subject, $id, $template) {
- global $lang;
- global $conf;
-
- $text = rawLocale($template);
- $trep = array_merge($replaces, array('PAGE' => $id));
- $hrep = $trep;
- $hrep['DIFF'] = nl2br(htmlspecialchars($hrep['DIFF']));
-
- $subject = $lang['mail_' . $subject] . ' ' . $id;
- $mail = new Mailer();
- $mail->bcc($subscriber_mail);
- $mail->subject($subject);
- $mail->setBody($text,$trep,$hrep);
- $mail->from($conf['mailfromnobody']);
- $mail->setHeader(
- 'List-Unsubscribe',
- '<'.wl($id,array('do'=>'subscribe'),true,'&').'>',
- false
- );
- return $mail->send();
-}
+function subscription_addresslist(&$data) {
+ $sub = new Subscription();
+ $sub->notifyaddresses($data);
+} \ No newline at end of file
diff --git a/inc/template.php b/inc/template.php
index 0d96be214..2c083c964 100644
--- a/inc/template.php
+++ b/inc/template.php
@@ -703,6 +703,7 @@ function tpl_get_action($type) {
}
break;
case 'media':
+ $params['ns'] = getNS($ID);
break;
default:
return '[unknown %s type]';
@@ -839,7 +840,9 @@ function tpl_youarehere($sep = ' » ') {
echo '<span class="bchead">'.$lang['youarehere'].': </span>';
// always print the startpage
+ echo '<span class="home">';
tpl_pagelink(':'.$conf['start']);
+ echo '</span>';
// print intermediate namespace links
$part = '';
@@ -1471,11 +1474,10 @@ function tpl_license($img = 'badge', $imgonly = false, $return = false, $wrap =
* template
*/
function tpl_include_page($pageid, $print = true, $propagate = false) {
- global $ID;
- global $TOC;
-
+ if (!$pageid) return false;
if ($propagate) $pageid = page_findnearest($pageid);
+ global $TOC;
$oldtoc = $TOC;
$html = p_wiki_xhtml($pageid, '', false);
$TOC = $oldtoc;
diff --git a/inc/utf8.php b/inc/utf8.php
index 6fab8502c..c944667f7 100644
--- a/inc/utf8.php
+++ b/inc/utf8.php
@@ -17,6 +17,25 @@ if(!defined('UTF8_MBSTRING')){
}
}
+/**
+ * Check if PREG was compiled with UTF-8 support
+ *
+ * Without this many of the functions below will not work, so this is a minimal requirement
+ */
+if(!defined('UTF8_PREGSUPPORT')){
+ define('UTF8_PREGSUPPORT', (bool) @preg_match('/^.$/u', 'ñ'));
+}
+
+/**
+ * Check if PREG was compiled with Unicode Property support
+ *
+ * This is not required for the functions below, but might be needed in a UTF-8 aware application
+ */
+if(!defined('UTF8_PROPERTYSUPPORT')){
+ define('UTF8_PROPERTYSUPPORT', (bool) @preg_match('/^\pL$/u', 'ñ'));
+}
+
+
if(UTF8_MBSTRING){ mb_internal_encoding('UTF-8'); }
if(!function_exists('utf8_isASCII')){