diff options
author | Brion Vibber <brion@pobox.com> | 2010-10-18 15:26:20 -0700 |
---|---|---|
committer | Brion Vibber <brion@pobox.com> | 2010-10-18 15:26:20 -0700 |
commit | f1bfbece06d7db20fa144fe5ac8a2f6c589eff45 (patch) | |
tree | 9804f314e8cd260819c9af059d9f50a47d7ee5b0 | |
parent | eb93bdbb038e8e22ee2bbcb84dbe3967672c48cf (diff) | |
parent | 140308bb03ecf99ac5738d6adbef066bf4e60461 (diff) |
Merge branch '1.0.x' into schema-x
-rw-r--r-- | README | 32 | ||||
-rw-r--r-- | actions/apidirectmessage.php | 6 | ||||
-rw-r--r-- | actions/apidirectmessagenew.php | 20 | ||||
-rw-r--r-- | actions/pathsadminpanel.php | 100 | ||||
-rw-r--r-- | actions/showfavorites.php | 14 | ||||
-rw-r--r-- | actions/shownotice.php | 2 | ||||
-rw-r--r-- | actions/showstream.php | 2 | ||||
-rw-r--r-- | install.php | 83 | ||||
-rw-r--r-- | lib/default.php | 3 | ||||
-rw-r--r-- | lib/dofollowlistitem.php | 88 | ||||
-rw-r--r-- | lib/installer.php | 42 | ||||
-rw-r--r-- | lib/util.php | 13 | ||||
-rw-r--r-- | plugins/DirectionDetector/DirectionDetectorPlugin.php | 3 | ||||
-rw-r--r-- | plugins/OStatus/tests/FeedDiscoveryTest.php | 9 | ||||
-rw-r--r-- | plugins/OStatus/tests/remote-tests.php | 44 | ||||
-rw-r--r-- | plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php | 3 | ||||
-rw-r--r-- | plugins/OpenID/openidadminpanel.php | 2 | ||||
-rw-r--r-- | tests/URLDetectionTest.php | 224 |
18 files changed, 492 insertions, 198 deletions
@@ -683,8 +683,9 @@ instructions; read to the end first before trying them. 6. Move your StatusNet directory to a backup spot, like "statusnet.bak". 7. Unpack your StatusNet 0.9.5 tarball and move it to "statusnet" or wherever your code used to be. -8. Copy the config.php file and avatar directory from your old - directory to your new directory. +8. Copy the config.php file and the contents of the avatar/, background/, + file/, and local/ subdirectories from your old directory to your new + directory. 9. Copy htaccess.sample to .htaccess in the new directory. Change the RewriteBase to use the correct path. 10. Rebuild the database. (You can safely skip this step and go to #12 @@ -1499,6 +1500,33 @@ disallow: Array of (virtual) directories to disallow. Default is 'main', 'search', 'message', 'settings', 'admin'. Ignored when site is private, in which case the entire site ('/') is disallowed. +api +--- + +Options for the Twitter-like API. + +realm: HTTP Basic Auth realm (see http://tools.ietf.org/html/rfc2617 + for details). Some third-party tools like ping.fm want this to be + 'Identi.ca API', so set it to that if you want to. default = null, + meaning 'something based on the site name'. + +nofollow +-------- + +We optionally put 'rel="nofollow"' on some links in some pages. The +following configuration settings let you fine-tune how or when things +are nofollowed. See http://en.wikipedia.org/wiki/Nofollow for more +information on what 'nofollow' means. + +subscribers: whether to nofollow links to subscribers on the profile + and personal pages. Default is true. +members: links to members on the group page. Default true. +peopletag: links to people listed in the peopletag page. Default true. +external: external links in notices. One of three values: 'sometimes', + 'always', 'never'. If 'sometimes', then external links are not + nofollowed on profile, notice, and favorites page. Default is + 'sometimes'. + url --- diff --git a/actions/apidirectmessage.php b/actions/apidirectmessage.php index e7ea38dfa..4e2ec5eb0 100644 --- a/actions/apidirectmessage.php +++ b/actions/apidirectmessage.php @@ -74,6 +74,7 @@ class ApiDirectMessageAction extends ApiAuthAction $this->user = $this->auth_user; if (empty($this->user)) { + // TRANS: Client error given when a user was not found (404). $this->clientError(_('No such user.'), 404, $this->format); return; } @@ -86,10 +87,12 @@ class ApiDirectMessageAction extends ApiAuthAction // Action was called by /api/direct_messages/sent.format $this->title = sprintf( + // TRANS: %s is a user nickname. _("Direct messages from %s"), $this->user->nickname ); $this->subtitle = sprintf( + // TRANS: %s is a user nickname. _("All the direct messages sent from %s"), $this->user->nickname ); @@ -98,10 +101,12 @@ class ApiDirectMessageAction extends ApiAuthAction $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id; } else { $this->title = sprintf( + // TRANS: %s is a user nickname. _("Direct messages to %s"), $this->user->nickname ); $this->subtitle = sprintf( + // TRANS: %s is a user nickname. _("All the direct messages sent to %s"), $this->user->nickname ); @@ -153,6 +158,7 @@ class ApiDirectMessageAction extends ApiAuthAction $this->showJsonDirectMessages(); break; default: + // TRANS: Client error given when an API method was not found (404). $this->clientError(_('API method not found.'), $code = 404); break; } diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php index 44e205ebb..c126cd312 100644 --- a/actions/apidirectmessagenew.php +++ b/actions/apidirectmessagenew.php @@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiauth.php'; * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class ApiDirectMessageNewAction extends ApiAuthAction { var $other = null; @@ -63,7 +62,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction * @return boolean success flag * */ - function prepare($args) { parent::prepare($args); @@ -99,7 +97,6 @@ class ApiDirectMessageNewAction extends ApiAuthAction * * @return void */ - function handle($args) { parent::handle($args); @@ -116,6 +113,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction if (empty($this->content)) { $this->clientError( + // TRANS: Client error (406). _('No message text!'), 406, $this->format @@ -123,9 +121,10 @@ class ApiDirectMessageNewAction extends ApiAuthAction } else { $content_shortened = common_shorten_links($this->content); if (Message::contentTooLong($content_shortened)) { + // TRANS: Client error displayed when message content is too long. + // TRANS: %d is the maximum number of characters for a message. $this->clientError( - sprintf( - _('That\'s too long. Max message size is %d chars.'), + sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()), Message::maxContent() ), 406, @@ -136,10 +135,12 @@ class ApiDirectMessageNewAction extends ApiAuthAction } if (empty($this->other)) { + // TRANS: Client error displayed if a recipient user could not be found (403). $this->clientError(_('Recipient user not found.'), 403, $this->format); return; } else if (!$this->user->mutuallySubscribed($this->other)) { $this->clientError( + // TRANS: Client error displayed trying to direct message another user who's not a friend (403). _('Can\'t send direct messages to users who aren\'t your friend.'), 403, $this->format @@ -149,10 +150,9 @@ class ApiDirectMessageNewAction extends ApiAuthAction // Note: sending msgs to yourself is allowed by Twitter - $errmsg = 'Don\'t send a message to yourself; ' . - 'just say it to yourself quietly instead.'; - - $this->clientError(_($errmsg), 403, $this->format); + // TRANS: Client error displayed trying to direct message self (403). + $this->clientError(_('Do not send a message to yourself; ' . + 'just say it to yourself quietly instead.'), 403, $this->format); return; } @@ -176,6 +176,4 @@ class ApiDirectMessageNewAction extends ApiAuthAction $this->showSingleJsondirectMessage($message); } } - } - diff --git a/actions/pathsadminpanel.php b/actions/pathsadminpanel.php index 0c83aa29e..e073b0a2a 100644 --- a/actions/pathsadminpanel.php +++ b/actions/pathsadminpanel.php @@ -92,16 +92,17 @@ class PathsadminpanelAction extends AdminPanelAction function saveSettings() { static $settings = array( - 'site' => array('path', 'locale_path', 'ssl', 'sslserver'), - 'theme' => array('server', 'dir', 'path'), - 'avatar' => array('server', 'dir', 'path'), - 'background' => array('server', 'dir', 'path') - ); + 'site' => array('path', 'locale_path', 'ssl', 'sslserver'), + 'theme' => array('server', 'dir', 'path', 'sslserver', 'sslpath'), + 'avatar' => array('server', 'dir', 'path'), + 'background' => array('server', 'dir', 'path', 'sslserver', 'sslpath'), + 'attachments' => array('server', 'dir', 'path', 'sslserver', 'sslpath') + ); - // XXX: If we're only going to have one boolean on thi page we - // can remove some of the boolean processing code --Z + // XXX: If we're only going to have one boolean on thi page we + // can remove some of the boolean processing code --Z - static $booleans = array('site' => array('fancy')); + static $booleans = array('site' => array('fancy')); $values = array(); @@ -131,13 +132,13 @@ class PathsadminpanelAction extends AdminPanelAction } } - foreach ($booleans as $section => $parts) { - foreach ($parts as $setting) { + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { Config::save($section, $setting, $values[$section][$setting]); } - } + } - $config->query('COMMIT'); + $config->query('COMMIT'); return; } @@ -230,11 +231,11 @@ class PathsAdminPanelForm extends AdminForm function formData() { - $this->out->elementStart('fieldset', array('id' => 'settings_paths_locale')); + $this->out->elementStart('fieldset', array('id' => 'settings_paths_locale')); $this->out->element('legend', null, _('Site'), 'site'); $this->out->elementStart('ul', 'form_data'); - $this->li(); + $this->li(); $this->input('server', _('Server'), _('Site\'s server hostname.')); $this->unli(); @@ -243,14 +244,14 @@ class PathsAdminPanelForm extends AdminForm $this->unli(); $this->li(); - $this->input('locale_path', _('Path to locales'), _('Directory path to locales'), 'site'); + $this->input('locale_path', _('Locale Directory'), _('Directory path to locales'), 'site'); $this->unli(); - $this->li(); + $this->li(); $this->out->checkbox('fancy', _('Fancy URLs'), (bool) $this->value('fancy'), _('Use fancy (more readable and memorable) URLs?')); - $this->unli(); + $this->unli(); $this->out->elementEnd('ul'); $this->out->elementEnd('fieldset'); @@ -261,15 +262,23 @@ class PathsAdminPanelForm extends AdminForm $this->out->elementStart('ul', 'form_data'); $this->li(); - $this->input('server', _('Theme server'), 'Server for themes', 'theme'); + $this->input('server', _('Server'), _('Server for themes'), 'theme'); + $this->unli(); + + $this->li(); + $this->input('path', _('Path'), _('Web path to themes'), 'theme'); + $this->unli(); + + $this->li(); + $this->input('sslserver', _('SSL server'), _('SSL server for themes (default: SSL server)'), 'theme'); $this->unli(); $this->li(); - $this->input('path', _('Theme path'), 'Web path to themes', 'theme'); + $this->input('sslpath', _('SSL path'), _('SSL path to themes (default: /theme/)'), 'theme'); $this->unli(); $this->li(); - $this->input('dir', _('Theme directory'), 'Directory where themes are located', 'theme'); + $this->input('dir', _('Directory'), _('Directory where themes are located'), 'theme'); $this->unli(); $this->out->elementEnd('ul'); @@ -297,20 +306,57 @@ class PathsAdminPanelForm extends AdminForm $this->out->elementEnd('fieldset'); $this->out->elementStart('fieldset', array('id' => - 'settings_design_background-paths')); + 'settings_design_background-paths')); $this->out->element('legend', null, _('Backgrounds')); $this->out->elementStart('ul', 'form_data'); $this->li(); - $this->input('server', _('Background server'), 'Server for backgrounds', 'background'); + $this->input('server', _('Server'), 'Server for backgrounds', 'background'); + $this->unli(); + + $this->li(); + $this->input('path', _('Path'), 'Web path to backgrounds', 'background'); $this->unli(); $this->li(); - $this->input('path', _('Background path'), 'Web path to backgrounds', 'background'); + $this->input('sslserver', _('SSL server'), 'Server for backgrounds on SSL pages', 'background'); $this->unli(); $this->li(); - $this->input('dir', _('Background directory'), 'Directory where backgrounds are located', 'background'); + $this->input('sslpath', _('SSL path'), 'Web path to backgrounds on SSL pages', 'background'); + $this->unli(); + + $this->li(); + $this->input('dir', _('Directory'), 'Directory where backgrounds are located', 'background'); + $this->unli(); + + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + + $this->out->elementStart('fieldset', array('id' => + 'settings_design_attachments-paths')); + + $this->out->element('legend', null, _('Attachments')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->input('server', _('Server'), 'Server for attachments', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('path', _('Path'), 'Web path to attachments', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('sslserver', _('SSL server'), 'Server for attachments on SSL pages', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('sslpath', _('SSL path'), 'Web path to attachments on SSL pages', 'attachments'); + $this->unli(); + + $this->li(); + $this->input('dir', _('Directory'), 'Directory where attachments are located', 'attachments'); $this->unli(); $this->out->elementEnd('ul'); @@ -320,12 +366,11 @@ class PathsAdminPanelForm extends AdminForm $this->out->element('legend', null, _('SSL')); $this->out->elementStart('ul', 'form_data'); $this->li(); + $ssl = array('never' => _('Never'), 'sometimes' => _('Sometimes'), 'always' => _('Always')); - common_debug("site ssl = " . $this->value('site', 'ssl')); - $this->out->dropdown('site-ssl', _('Use SSL'), $ssl, _('When to use SSL'), false, $this->value('ssl', 'site')); @@ -349,7 +394,7 @@ class PathsAdminPanelForm extends AdminForm function formActions() { $this->out->submit('save', _('Save'), 'submit', - 'save', _('Save paths')); + 'save', _('Save paths')); } /** @@ -370,5 +415,4 @@ class PathsAdminPanelForm extends AdminForm { $this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions); } - } diff --git a/actions/showfavorites.php b/actions/showfavorites.php index d8042e91c..77b73711d 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -227,7 +227,7 @@ class ShowfavoritesAction extends OwnerDesignAction function showContent() { - $nl = new NoticeList($this->notice, $this); + $nl = new FavoritesNoticeList($this->notice, $this); $cnt = $nl->show(); if (0 == $cnt) { @@ -244,3 +244,15 @@ class ShowfavoritesAction extends OwnerDesignAction } } +class FavoritesNoticeList extends NoticeList +{ + function newListItem($notice) + { + return new FavoritesNoticeListItem($notice, $this->out); + } +} + +// All handled by superclass +class FavoritesNoticeListItem extends DoFollowListItem +{ +} diff --git a/actions/shownotice.php b/actions/shownotice.php index 93d056aca..5b3ec93de 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -305,7 +305,7 @@ class ShownoticeAction extends OwnerDesignAction } } -class SingleNoticeItem extends NoticeListItem +class SingleNoticeItem extends DoFollowListItem { /** * recipe function for displaying a single notice. diff --git a/actions/showstream.php b/actions/showstream.php index b2082eb4b..8178dafb1 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -269,7 +269,7 @@ class ProfileNoticeList extends NoticeList } } -class ProfileNoticeListItem extends NoticeListItem +class ProfileNoticeListItem extends DoFollowListItem { function showAuthor() { diff --git a/install.php b/install.php index 158d51fa3..9b0d19882 100644 --- a/install.php +++ b/install.php @@ -45,13 +45,61 @@ require INSTALLDIR . '/lib/installer.php'; * Helper class for building form */ class Posted { + /** + * HTML-friendly escaped string for the POST param of given name, or empty. + * @param string $name + * @return string + */ function value($name) { + return htmlspecialchars($this->string($name)); + } + + /** + * The given POST parameter value, forced to a string. + * Missing value will give ''. + * + * @param string $name + * @return string + */ + function string($name) + { + return strval($this->raw($name)); + } + + /** + * The given POST parameter value, in its original form. + * Magic quotes are stripped, if provided. + * Missing value will give null. + * + * @param string $name + * @return mixed + */ + function raw($name) + { if (isset($_POST[$name])) { - return htmlspecialchars(strval($_POST[$name])); + return $this->dequote($_POST[$name]); } else { - return ''; + return null; + } + } + + /** + * If necessary, strip magic quotes from the given value. + * + * @param mixed $val + * @return mixed + */ + function dequote($val) + { + if (get_magic_quotes_gpc()) { + if (is_string($val)) { + return stripslashes($val); + } else if (is_array($val)) { + return array_map(array($this, 'dequote'), $val); + } } + return $val; } } @@ -107,11 +155,7 @@ class WebInstaller extends Installer global $dbModules; $post = new Posted(); $dbRadios = ''; - if (isset($_POST['dbtype'])) { - $dbtype = $_POST['dbtype']; - } else { - $dbtype = null; - } + $dbtype = $post->raw('dbtype'); foreach (self::$dbModules as $type => $info) { if ($this->checkExtension($info['check_module'])) { if ($dbtype == null || $dbtype == $type) { @@ -245,19 +289,20 @@ STR; */ function prepare() { - $this->host = $_POST['host']; - $this->dbtype = $_POST['dbtype']; - $this->database = $_POST['database']; - $this->username = $_POST['dbusername']; - $this->password = $_POST['dbpassword']; - $this->sitename = $_POST['sitename']; - $this->fancy = !empty($_POST['fancy']); + $post = new Posted(); + $this->host = $post->string('host'); + $this->dbtype = $post->string('dbtype'); + $this->database = $post->string('database'); + $this->username = $post->string('dbusername'); + $this->password = $post->string('dbpassword'); + $this->sitename = $post->string('sitename'); + $this->fancy = (bool)$post->string('fancy'); - $this->adminNick = strtolower($_POST['admin_nickname']); - $this->adminPass = $_POST['admin_password']; - $adminPass2 = $_POST['admin_password2']; - $this->adminEmail = $_POST['admin_email']; - $this->adminUpdates = $_POST['admin_updates']; + $this->adminNick = strtolower($post->string('admin_nickname')); + $this->adminPass = $post->string('admin_password'); + $adminPass2 = $post->string('admin_password2'); + $this->adminEmail = $post->string('admin_email'); + $this->adminUpdates = $post->string('admin_updates'); $this->server = $_SERVER['HTTP_HOST']; $this->path = substr(dirname($_SERVER['PHP_SELF']), 1); diff --git a/lib/default.php b/lib/default.php index 279a7a3d1..a1dac7b5e 100644 --- a/lib/default.php +++ b/lib/default.php @@ -319,7 +319,8 @@ $default = 'nofollow' => array('subscribers' => true, 'members' => true, - 'peopletag' => true), + 'peopletag' => true, + 'external' => 'sometimes'), // Options: 'sometimes', 'never', default = 'sometimes' 'url' => array('shortener' => 'ur1.ca', 'maxlength' => 25, diff --git a/lib/dofollowlistitem.php b/lib/dofollowlistitem.php new file mode 100644 index 000000000..80e2d0b0a --- /dev/null +++ b/lib/dofollowlistitem.php @@ -0,0 +1,88 @@ +<?php +/** + * StatusNet, the distributed open-source microblogging tool + * + * widget for displaying a list of notices + * + * PHP version 5 + * + * LICENCE: This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @category UI + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/noticelist.php'; + +/** + * StatusNet, the distributed open-source microblogging tool + * + * Widget superclass for notice list items that remove rel=nofollow + * + * When nofollow|external = 'sometimes', notices get rendered and saved + * with rel=nofollow for external links. We want to remove that relationship + * on some pages (profile, single notice, faves). This superclass for + * some noticelistitems will strip that bit of code out when showing + * notice content + * + * @category UI + * @package StatusNet + * @author Evan Prodromou <evan@status.net> + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 + * @link http://status.net/ + */ + +class DoFollowListItem extends NoticeListItem +{ + /** + * show the content of the notice + * + * Trims out the rel=nofollow for external links + * if nofollow|external = 'sometimes' + * + * @return void + */ + + function showContent() + { + // FIXME: URL, image, video, audio + $this->out->elementStart('p', array('class' => 'entry-content')); + + if (!empty($this->notice->rendered)) { + $html = $this->notice->rendered; + } else { + $html = common_render_content($this->notice->content, $this->notice); + } + + if (common_config('nofollow', 'external') == 'sometimes') { + // remove the nofollow part + // XXX: cache the results here + + $html = preg_replace('/rel="(.*)nofollow ?/', 'rel="\1', $html); + } + + $this->out->raw($html); + + $this->out->elementEnd('p'); + } +}
\ No newline at end of file diff --git a/lib/installer.php b/lib/installer.php index a5588fbed..441f72660 100644 --- a/lib/installer.php +++ b/lib/installer.php @@ -356,6 +356,30 @@ abstract class Installer } /** + * Return a parseable PHP literal for the given value. + * This will include quotes for strings, etc. + * + * @param mixed $val + * @return string + */ + function phpVal($val) + { + return var_export($val, true); + } + + /** + * Return an array of parseable PHP literal for the given values. + * These will include quotes for strings, etc. + * + * @param mixed $val + * @return array + */ + function phpVals($map) + { + return array_map(array($this, 'phpVal'), $map); + } + + /** * Write a stock configuration file. * * @return boolean success @@ -364,24 +388,32 @@ abstract class Installer */ function writeConf() { + $vals = $this->phpVals(array( + 'sitename' => $this->sitename, + 'server' => $this->server, + 'path' => $this->path, + 'db_database' => $this->db['database'], + 'db_type' => $this->db['type'], + )); + // assemble configuration file in a string $cfg = "<?php\n". "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n". // site name - "\$config['site']['name'] = '{$this->sitename}';\n\n". + "\$config['site']['name'] = {$vals['sitename']};\n\n". // site location - "\$config['site']['server'] = '{$this->server}';\n". - "\$config['site']['path'] = '{$this->path}'; \n\n". + "\$config['site']['server'] = {$vals['server']};\n". + "\$config['site']['path'] = {$vals['path']}; \n\n". // checks if fancy URLs are enabled ($this->fancy ? "\$config['site']['fancy'] = true;\n\n":''). // database - "\$config['db']['database'] = '{$this->db['database']}';\n\n". + "\$config['db']['database'] = {$vals['db_database']};\n\n". ($this->db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":''). - "\$config['db']['type'] = '{$this->db['type']}';\n\n"; + "\$config['db']['type'] = {$vals['db_type']};\n\n"; // Normalize line endings for Windows servers $cfg = str_replace("\n", PHP_EOL, $cfg); diff --git a/lib/util.php b/lib/util.php index 85d7c72f4..1d7cffe41 100644 --- a/lib/util.php +++ b/lib/util.php @@ -875,7 +875,8 @@ function common_linkify($url) { $longurl = $url; } } - $attrs = array('href' => $canon, 'title' => $longurl, 'rel' => 'external'); + + $attrs = array('href' => $canon, 'title' => $longurl); $is_attachment = false; $attachment_id = null; @@ -911,6 +912,16 @@ function common_linkify($url) { $attrs['id'] = "attachment-{$attachment_id}"; } + // Whether to nofollow + + $nf = common_config('nofollow', 'external'); + + if ($nf == 'never') { + $attrs['rel'] = 'external'; + } else { + $attrs['rel'] = 'nofollow external'; + } + return XMLStringer::estring('a', $attrs, $url); } diff --git a/plugins/DirectionDetector/DirectionDetectorPlugin.php b/plugins/DirectionDetector/DirectionDetectorPlugin.php index 1473c386f..4a38f390f 100644 --- a/plugins/DirectionDetector/DirectionDetectorPlugin.php +++ b/plugins/DirectionDetector/DirectionDetectorPlugin.php @@ -81,6 +81,9 @@ class DirectionDetectorPlugin extends Plugin { * @return boolean */ public static function startsWithRTLCharacter($str){ + if (strlen($str) < 1) { + return false; + } if( is_array($cc = self::utf8ToUnicode(mb_substr($str, 0, 1, 'utf-8'))) ) $cc = $cc[0]; else diff --git a/plugins/OStatus/tests/FeedDiscoveryTest.php b/plugins/OStatus/tests/FeedDiscoveryTest.php index 3be4bf736..ef17efe7c 100644 --- a/plugins/OStatus/tests/FeedDiscoveryTest.php +++ b/plugins/OStatus/tests/FeedDiscoveryTest.php @@ -75,9 +75,10 @@ END; '<body><pre><LINK rel=alternate hRef=http://example.com/feed/rss type=application/rss+xml><fnork', 'http://example.com/feed/rss'), // 'rel' attribute must be lowercase, alone per http://www.rssboard.org/rss-autodiscovery + // but we're going to be liberal in what we receive. array('http://example.com/tagsoup2', '<body><pre><LINK rel=" feeders alternate 467" hRef=http://example.com/feed/rss type=application/rss+xml><fnork', - false), + 'http://example.com/feed/rss'), array('http://example.com/tagsoup3', '<body><pre><LINK rel=ALTERNATE hRef=http://example.com/feed/rss type=application/rss+xml><fnork', false), @@ -87,18 +88,20 @@ END; array('http://example.com/relative/link2', '<html><link rel="alternate" href="../feed/rss" type="application/rss+xml">', 'http://example.com/feed/rss'), + // This one can't resolve correctly; relative link is bogus. array('http://example.com/relative/link3', '<html><link rel="alternate" href="http:/feed/rss" type="application/rss+xml">', - 'http://example.com/feed/rss'), + 'http:/feed/rss'), array('http://example.com/base/link1', '<html><link rel="alternate" href="/feed/rss" type="application/rss+xml"><base href="http://target.example.com/">', 'http://target.example.com/feed/rss'), array('http://example.com/base/link2', '<html><link rel="alternate" href="feed/rss" type="application/rss+xml"><base href="http://target.example.com/">', 'http://target.example.com/feed/rss'), + // This one can't resolve; relative link is bogus. array('http://example.com/base/link3', '<html><link rel="alternate" href="http:/feed/rss" type="application/rss+xml"><base href="http://target.example.com/">', - 'http://target.example.com/feed/rss'), + 'http:/feed/rss'), // Trick question! There's a <base> but no href on it array('http://example.com/relative/fauxbase', '<html><link rel="alternate" href="../feed/rss" type="application/rss+xml"><base target="top">', diff --git a/plugins/OStatus/tests/remote-tests.php b/plugins/OStatus/tests/remote-tests.php index 64c60a8a4..7888ec7c5 100644 --- a/plugins/OStatus/tests/remote-tests.php +++ b/plugins/OStatus/tests/remote-tests.php @@ -4,7 +4,7 @@ if (php_sapi_name() != 'cli') { die('not for web'); } -define('TIMEOUT', 60); // ssslllloowwwww salmon if queues are off +define('HTTP_TIMEOUT', 60); // ssslllloowwwww salmon if queues are off define('INSTALLDIR', dirname(dirname(dirname(dirname(__FILE__))))); set_include_path(INSTALLDIR . '/extlib' . PATH_SEPARATOR . get_include_path()); @@ -63,14 +63,15 @@ class OStatusTester extends TestBase /** * @param string $a base URL of test site A (eg http://localhost/mublog) * @param string $b base URL of test site B (eg http://localhost/mublog2) + * @param int $timeout HTTP timeout value (needs to be long if Salmon is slow) */ - function __construct($a, $b) { + function __construct($a, $b, $timeout=60) { $this->a = $a; $this->b = $b; $base = 'test' . mt_rand(1, 1000000); - $this->pub = new SNTestClient($this->a, 'pub' . $base, 'pw-' . mt_rand(1, 1000000)); - $this->sub = new SNTestClient($this->b, 'sub' . $base, 'pw-' . mt_rand(1, 1000000)); + $this->pub = new SNTestClient($this->a, 'pub' . $base, 'pw-' . mt_rand(1, 1000000), $timeout); + $this->sub = new SNTestClient($this->b, 'sub' . $base, 'pw-' . mt_rand(1, 1000000), $timeout); } function run() @@ -166,11 +167,12 @@ class OStatusTester extends TestBase class SNTestClient extends TestBase { - function __construct($base, $username, $password) + function __construct($base, $username, $password, $timeout=60) { $this->basepath = $base; $this->username = $username; $this->password = $password; + $this->timeout = $timeout; $this->fullname = ucfirst($username) . ' Smith'; $this->homepage = 'http://example.org/' . $username; @@ -190,7 +192,7 @@ class SNTestClient extends TestBase { $url = $this->basepath . '/' . $path; - $http = new HTTP_Request2($url, 'POST', array('timeout' => TIMEOUT)); + $http = new HTTP_Request2($url, 'POST', array('timeout' => $this->timeout)); if ($auth) { $http->setAuth($this->username, $this->password, HTTP_Request2::AUTH_BASIC); } @@ -217,7 +219,7 @@ class SNTestClient extends TestBase protected function web($path, $form, $params=array()) { $url = $this->basepath . '/' . $path; - $http = new HTTP_Request2($url, 'GET', array('timeout' => TIMEOUT)); + $http = new HTTP_Request2($url, 'GET', array('timeout' => $this->timeout)); $response = $http->send(); $dom = $this->checkWeb($url, 'GET', $response); @@ -534,10 +536,29 @@ class SNTestClient extends TestBase } -$args = array_slice($_SERVER['argv'], 1); +// @fixme switch to commandline.inc? +$timeout = HTTP_TIMEOUT; + +$args = array(); +$options = array(); +foreach (array_slice($_SERVER['argv'], 1) as $arg) { + if (substr($arg, 0, 2) == '--') { + $bits = explode('=', substr($arg, 2), 2); + if (count($bits == 2)) { + list($key, $val) = $bits; + $options[$key] = $val; + } else { + list($key) = $bits; + $options[$key] = true; + } + } else { + $args[] = $arg; + } +} if (count($args) < 2) { print <<<END_HELP -remote-tests.php <url1> <url2> +remote-tests.php [options] <url1> <url2> + --timeout=## change HTTP timeout from default {$timeout}s url1: base URL of a StatusNet instance url2: base URL of another StatusNet instance @@ -551,6 +572,9 @@ exit(1); $a = $args[0]; $b = $args[1]; +if (isset($options['timeout'])) { + $timeout = intval($options['timeout']); +} -$tester = new OStatusTester($a, $b); +$tester = new OStatusTester($a, $b, $timeout); $tester->run(); diff --git a/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php b/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php index 611f5e5c7..f0f6144e0 100644 --- a/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php +++ b/plugins/OpenExternalLinkTarget/OpenExternalLinkTargetPlugin.php @@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ - class OpenExternalLinkTargetPlugin extends Plugin { function onEndShowScripts($action) @@ -57,7 +56,7 @@ class OpenExternalLinkTargetPlugin extends Plugin 'author' => 'Sarven Capadisli', 'homepage' => 'http://status.net/wiki/Plugin:OpenExternalLinkTarget', 'rawdescription' => - _m('Opens external links (e.g., with rel=external) on a new window or tab.')); + _m('Opens external links (i.e. with rel=external) on a new window or tab.')); return true; } } diff --git a/plugins/OpenID/openidadminpanel.php b/plugins/OpenID/openidadminpanel.php index ce4806cc8..38df183fe 100644 --- a/plugins/OpenID/openidadminpanel.php +++ b/plugins/OpenID/openidadminpanel.php @@ -257,7 +257,7 @@ class OpenIDAdminPanelForm extends AdminForm $this->out->checkbox( 'openidonly', _m('Enable OpenID-only mode'), (bool) $this->value('openidonly', 'site'), - _m('Require all users to login via OpenID. WARNING: disables password authentication for all users!'), + _m('Require all users to login via OpenID. Warning: disables password authentication for all users!'), 'true' ); $this->unli(); diff --git a/tests/URLDetectionTest.php b/tests/URLDetectionTest.php index d83f9faf5..eac7ba3f5 100644 --- a/tests/URLDetectionTest.php +++ b/tests/URLDetectionTest.php @@ -29,73 +29,73 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('not a link :: no way', 'not a link :: no way'), array('link http://www.somesite.com/xyz/35637563@N00/52803365/ link', - 'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" title="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="external">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'), + 'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" title="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="nofollow external">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'), array('http://127.0.0.1', - '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'), + '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">http://127.0.0.1</a>'), array('127.0.0.1', - '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">127.0.0.1</a>'), + '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">127.0.0.1</a>'), array('127.0.0.1:99', - '<a href="http://127.0.0.1:99/" title="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'), + '<a href="http://127.0.0.1:99/" title="http://127.0.0.1:99/" rel="nofollow external">127.0.0.1:99</a>'), array('127.0.0.1/Name:test.php', - '<a href="http://127.0.0.1/Name:test.php" title="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'), + '<a href="http://127.0.0.1/Name:test.php" title="http://127.0.0.1/Name:test.php" rel="nofollow external">127.0.0.1/Name:test.php</a>'), array('127.0.0.1/~test', - '<a href="http://127.0.0.1/~test" title="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'), + '<a href="http://127.0.0.1/~test" title="http://127.0.0.1/~test" rel="nofollow external">127.0.0.1/~test</a>'), array('127.0.0.1/+test', - '<a href="http://127.0.0.1/+test" title="http://127.0.0.1/+test" rel="external">127.0.0.1/+test</a>'), + '<a href="http://127.0.0.1/+test" title="http://127.0.0.1/+test" rel="nofollow external">127.0.0.1/+test</a>'), array('127.0.0.1/$test', - '<a href="http://127.0.0.1/$test" title="http://127.0.0.1/$test" rel="external">127.0.0.1/$test</a>'), + '<a href="http://127.0.0.1/$test" title="http://127.0.0.1/$test" rel="nofollow external">127.0.0.1/$test</a>'), array('127.0.0.1/\'test', - '<a href="http://127.0.0.1/\'test" title="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'), + '<a href="http://127.0.0.1/\'test" title="http://127.0.0.1/\'test" rel="nofollow external">127.0.0.1/\'test</a>'), array('127.0.0.1/"test', - '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">127.0.0.1/</a>"test'), + '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">127.0.0.1/</a>"test'), array('127.0.0.1/test"test', - '<a href="http://127.0.0.1/test" title="http://127.0.0.1/test" rel="external">127.0.0.1/test</a>"test'), + '<a href="http://127.0.0.1/test" title="http://127.0.0.1/test" rel="nofollow external">127.0.0.1/test</a>"test'), array('127.0.0.1/-test', - '<a href="http://127.0.0.1/-test" title="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'), + '<a href="http://127.0.0.1/-test" title="http://127.0.0.1/-test" rel="nofollow external">127.0.0.1/-test</a>'), array('127.0.0.1/_test', - '<a href="http://127.0.0.1/_test" title="http://127.0.0.1/_test" rel="external">127.0.0.1/_test</a>'), + '<a href="http://127.0.0.1/_test" title="http://127.0.0.1/_test" rel="nofollow external">127.0.0.1/_test</a>'), array('127.0.0.1/!test', - '<a href="http://127.0.0.1/!test" title="http://127.0.0.1/!test" rel="external">127.0.0.1/!test</a>'), + '<a href="http://127.0.0.1/!test" title="http://127.0.0.1/!test" rel="nofollow external">127.0.0.1/!test</a>'), array('127.0.0.1/*test', - '<a href="http://127.0.0.1/*test" title="http://127.0.0.1/*test" rel="external">127.0.0.1/*test</a>'), + '<a href="http://127.0.0.1/*test" title="http://127.0.0.1/*test" rel="nofollow external">127.0.0.1/*test</a>'), array('127.0.0.1/test%20stuff', - '<a href="http://127.0.0.1/test%20stuff" title="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'), + '<a href="http://127.0.0.1/test%20stuff" title="http://127.0.0.1/test%20stuff" rel="nofollow external">127.0.0.1/test%20stuff</a>'), array('http://[::1]:99/test.php', - '<a href="http://[::1]:99/test.php" title="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'), + '<a href="http://[::1]:99/test.php" title="http://[::1]:99/test.php" rel="nofollow external">http://[::1]:99/test.php</a>'), array('http://::1/test.php', - '<a href="http://::1/test.php" title="http://::1/test.php" rel="external">http://::1/test.php</a>'), + '<a href="http://::1/test.php" title="http://::1/test.php" rel="nofollow external">http://::1/test.php</a>'), array('http://::1', - '<a href="http://::1/" title="http://::1/" rel="external">http://::1</a>'), + '<a href="http://::1/" title="http://::1/" rel="nofollow external">http://::1</a>'), array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php', - '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>'), + '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="nofollow external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>'), array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php', - '<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" title="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>'), + '<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" title="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="nofollow external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>'), array('2001:4978:1b5:0:21d:e0ff:fe66:59ab', - '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>'), + '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" title="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="nofollow external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>'), array('http://127.0.0.1', - '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'), + '<a href="http://127.0.0.1/" title="http://127.0.0.1/" rel="nofollow external">http://127.0.0.1</a>'), array('example.com', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>'), array('example.com', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>'), array('http://example.com', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>'), array('http://example.com.', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>.'), array('/var/lib/example.so', '/var/lib/example.so'), array('example', 'example'), array('user@example.com', - '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="external">user@example.com</a>'), + '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="nofollow external">user@example.com</a>'), array('user_name+other@example.com', - '<a href="mailto:user_name+other@example.com" title="mailto:user_name+other@example.com" rel="external">user_name+other@example.com</a>'), + '<a href="mailto:user_name+other@example.com" title="mailto:user_name+other@example.com" rel="nofollow external">user_name+other@example.com</a>'), array('mailto:user@example.com', - '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="external">mailto:user@example.com</a>'), + '<a href="mailto:user@example.com" title="mailto:user@example.com" rel="nofollow external">mailto:user@example.com</a>'), array('mailto:user@example.com?subject=test', - '<a href="mailto:user@example.com?subject=test" title="mailto:user@example.com?subject=test" rel="external">mailto:user@example.com?subject=test</a>'), + '<a href="mailto:user@example.com?subject=test" title="mailto:user@example.com?subject=test" rel="nofollow external">mailto:user@example.com?subject=test</a>'), array('xmpp:user@example.com', - '<a href="xmpp:user@example.com" title="xmpp:user@example.com" rel="external">xmpp:user@example.com</a>'), + '<a href="xmpp:user@example.com" title="xmpp:user@example.com" rel="nofollow external">xmpp:user@example.com</a>'), array('#example', '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example'))) . '" rel="tag">example</a></span>'), array('#example.com', @@ -103,167 +103,167 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase array('#.net', '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('.net'))) . '" rel="tag">.net</a></span>'), array('http://example', - '<a href="http://example/" title="http://example/" rel="external">http://example</a>'), + '<a href="http://example/" title="http://example/" rel="nofollow external">http://example</a>'), array('http://3xampl3', - '<a href="http://3xampl3/" title="http://3xampl3/" rel="external">http://3xampl3</a>'), + '<a href="http://3xampl3/" title="http://3xampl3/" rel="nofollow external">http://3xampl3</a>'), array('http://example/', - '<a href="http://example/" title="http://example/" rel="external">http://example/</a>'), + '<a href="http://example/" title="http://example/" rel="nofollow external">http://example/</a>'), array('http://example/path', - '<a href="http://example/path" title="http://example/path" rel="external">http://example/path</a>'), + '<a href="http://example/path" title="http://example/path" rel="nofollow external">http://example/path</a>'), array('http://example.com', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>'), array('https://example.com', - '<a href="https://example.com/" title="https://example.com/" rel="external">https://example.com</a>'), + '<a href="https://example.com/" title="https://example.com/" rel="nofollow external">https://example.com</a>'), array('ftp://example.com', - '<a href="ftp://example.com/" title="ftp://example.com/" rel="external">ftp://example.com</a>'), + '<a href="ftp://example.com/" title="ftp://example.com/" rel="nofollow external">ftp://example.com</a>'), array('ftps://example.com', - '<a href="ftps://example.com/" title="ftps://example.com/" rel="external">ftps://example.com</a>'), + '<a href="ftps://example.com/" title="ftps://example.com/" rel="nofollow external">ftps://example.com</a>'), array('http://user@example.com', - '<a href="http://user@example.com/" title="http://user@example.com/" rel="external">http://user@example.com</a>'), + '<a href="http://user@example.com/" title="http://user@example.com/" rel="nofollow external">http://user@example.com</a>'), array('http://user:pass@example.com', - '<a href="http://user:pass@example.com/" title="http://user:pass@example.com/" rel="external">http://user:pass@example.com</a>'), + '<a href="http://user:pass@example.com/" title="http://user:pass@example.com/" rel="nofollow external">http://user:pass@example.com</a>'), array('http://example.com:8080', - '<a href="http://example.com:8080/" title="http://example.com:8080/" rel="external">http://example.com:8080</a>'), + '<a href="http://example.com:8080/" title="http://example.com:8080/" rel="nofollow external">http://example.com:8080</a>'), array('http://example.com:8080/test.php', - '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="external">http://example.com:8080/test.php</a>'), + '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="nofollow external">http://example.com:8080/test.php</a>'), array('example.com:8080/test.php', - '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="external">example.com:8080/test.php</a>'), + '<a href="http://example.com:8080/test.php" title="http://example.com:8080/test.php" rel="nofollow external">example.com:8080/test.php</a>'), array('http://www.example.com', - '<a href="http://www.example.com/" title="http://www.example.com/" rel="external">http://www.example.com</a>'), + '<a href="http://www.example.com/" title="http://www.example.com/" rel="nofollow external">http://www.example.com</a>'), array('http://example.com/', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com/</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com/</a>'), array('http://example.com/path', - '<a href="http://example.com/path" title="http://example.com/path" rel="external">http://example.com/path</a>'), + '<a href="http://example.com/path" title="http://example.com/path" rel="nofollow external">http://example.com/path</a>'), array('http://example.com/path.html', - '<a href="http://example.com/path.html" title="http://example.com/path.html" rel="external">http://example.com/path.html</a>'), + '<a href="http://example.com/path.html" title="http://example.com/path.html" rel="nofollow external">http://example.com/path.html</a>'), array('http://example.com/path.html#fragment', - '<a href="http://example.com/path.html#fragment" title="http://example.com/path.html#fragment" rel="external">http://example.com/path.html#fragment</a>'), + '<a href="http://example.com/path.html#fragment" title="http://example.com/path.html#fragment" rel="nofollow external">http://example.com/path.html#fragment</a>'), array('http://example.com/path.php?foo=bar&bar=foo', - '<a href="http://example.com/path.php?foo=bar&bar=foo" title="http://example.com/path.php?foo=bar&bar=foo" rel="external">http://example.com/path.php?foo=bar&bar=foo</a>'), + '<a href="http://example.com/path.php?foo=bar&bar=foo" title="http://example.com/path.php?foo=bar&bar=foo" rel="nofollow external">http://example.com/path.php?foo=bar&bar=foo</a>'), array('http://example.com.', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>.'), array('http://müllärör.de', - '<a href="http://müllärör.de/" title="http://müllärör.de/" rel="external">http://müllärör.de</a>'), + '<a href="http://müllärör.de/" title="http://müllärör.de/" rel="nofollow external">http://müllärör.de</a>'), array('http://ﺱﺲﺷ.com', - '<a href="http://ﺱﺲﺷ.com/" title="http://ﺱﺲﺷ.com/" rel="external">http://ﺱﺲﺷ.com</a>'), + '<a href="http://ﺱﺲﺷ.com/" title="http://ﺱﺲﺷ.com/" rel="nofollow external">http://ﺱﺲﺷ.com</a>'), array('http://сделаткартинки.com', - '<a href="http://сделаткартинки.com/" title="http://сделаткартинки.com/" rel="external">http://сделаткартинки.com</a>'), + '<a href="http://сделаткартинки.com/" title="http://сделаткартинки.com/" rel="nofollow external">http://сделаткартинки.com</a>'), array('http://tūdaliņ.lv', - '<a href="http://tūdaliņ.lv/" title="http://tūdaliņ.lv/" rel="external">http://tūdaliņ.lv</a>'), + '<a href="http://tūdaliņ.lv/" title="http://tūdaliņ.lv/" rel="nofollow external">http://tūdaliņ.lv</a>'), array('http://brændendekærlighed.com', - '<a href="http://brændendekærlighed.com/" title="http://brændendekærlighed.com/" rel="external">http://brændendekærlighed.com</a>'), + '<a href="http://brændendekærlighed.com/" title="http://brændendekærlighed.com/" rel="nofollow external">http://brændendekærlighed.com</a>'), array('http://あーるいん.com', - '<a href="http://あーるいん.com/" title="http://あーるいん.com/" rel="external">http://あーるいん.com</a>'), + '<a href="http://あーるいん.com/" title="http://あーるいん.com/" rel="nofollow external">http://あーるいん.com</a>'), array('http://예비교사.com', - '<a href="http://예비교사.com/" title="http://예비교사.com/" rel="external">http://예비교사.com</a>'), + '<a href="http://예비교사.com/" title="http://예비교사.com/" rel="nofollow external">http://예비교사.com</a>'), array('http://example.com.', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>.'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>.'), array('http://example.com?', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>?'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>?'), array('http://example.com!', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>!'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>!'), array('http://example.com,', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>,'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>,'), array('http://example.com;', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>;'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>;'), array('http://example.com:', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>:'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>:'), array('\'http://example.com\'', - '\'<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>\''), + '\'<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>\''), array('"http://example.com"', - '"<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>"'), + '"<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>"'), array('"http://example.com/"', - '"<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com/</a>"'), + '"<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com/</a>"'), array('http://example.com', - '<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>'), array('(http://example.com)', - '(<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>)'), + '(<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>)'), array('[http://example.com]', - '[<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>]'), + '[<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>]'), array('<http://example.com>', - '<<a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a>>'), + '<<a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a>>'), array('http://example.com/path/(foo)/bar', - '<a href="http://example.com/path/(foo)/bar" title="http://example.com/path/(foo)/bar" rel="external">http://example.com/path/(foo)/bar</a>'), + '<a href="http://example.com/path/(foo)/bar" title="http://example.com/path/(foo)/bar" rel="nofollow external">http://example.com/path/(foo)/bar</a>'), array('http://example.com/path/[foo]/bar', - '<a href="http://example.com/path/" title="http://example.com/path/" rel="external">http://example.com/path/</a>[foo]/bar'), + '<a href="http://example.com/path/" title="http://example.com/path/" rel="nofollow external">http://example.com/path/</a>[foo]/bar'), array('http://example.com/path/foo/(bar)', - '<a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>'), + '<a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">http://example.com/path/foo/(bar)</a>'), //Not a valid url - urls cannot contain unencoded square brackets array('http://example.com/path/foo/[bar]', - '<a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="external">http://example.com/path/foo/</a>[bar]'), + '<a href="http://example.com/path/foo/" title="http://example.com/path/foo/" rel="nofollow external">http://example.com/path/foo/</a>[bar]'), array('Hey, check out my cool site http://example.com okay?', - 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">http://example.com</a> okay?'), + 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">http://example.com</a> okay?'), array('What about parens (e.g. http://example.com/path/foo/(bar))?', - 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)?'), + 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">http://example.com/path/foo/(bar)</a>)?'), array('What about parens (e.g. http://example.com/path/foo/(bar)?', - 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>?'), + 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">http://example.com/path/foo/(bar)</a>?'), array('What about parens (e.g. http://example.com/path/foo/(bar).)?', - 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>.)?'), + 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">http://example.com/path/foo/(bar)</a>.)?'), //Not a valid url - urls cannot contain unencoded commas array('What about parens (e.g. http://example.com/path/(foo,bar)?', - 'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="external">http://example.com/path/(foo,bar)</a>?'), + 'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="nofollow external">http://example.com/path/(foo,bar)</a>?'), array('Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?', - 'Unbalanced too (e.g. <a href="http://example.com/path/((((foo)/bar)" title="http://example.com/path/((((foo)/bar)" rel="external">http://example.com/path/((((foo)/bar)</a>?'), + 'Unbalanced too (e.g. <a href="http://example.com/path/((((foo)/bar)" title="http://example.com/path/((((foo)/bar)" rel="nofollow external">http://example.com/path/((((foo)/bar)</a>?'), array('Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?', - 'Unbalanced too (e.g. <a href="http://example.com/path/(foo))))/bar" title="http://example.com/path/(foo))))/bar" rel="external">http://example.com/path/(foo))))/bar</a>)?'), + 'Unbalanced too (e.g. <a href="http://example.com/path/(foo))))/bar" title="http://example.com/path/(foo))))/bar" rel="nofollow external">http://example.com/path/(foo))))/bar</a>)?'), array('Unbalanced too (e.g. http://example.com/path/foo/((((bar)?', - 'Unbalanced too (e.g. <a href="http://example.com/path/foo/((((bar)" title="http://example.com/path/foo/((((bar)" rel="external">http://example.com/path/foo/((((bar)</a>?'), + 'Unbalanced too (e.g. <a href="http://example.com/path/foo/((((bar)" title="http://example.com/path/foo/((((bar)" rel="nofollow external">http://example.com/path/foo/((((bar)</a>?'), array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?', - 'Unbalanced too (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)))?'), + 'Unbalanced too (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">http://example.com/path/foo/(bar)</a>)))?'), array('example.com', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>'), array('example.org', - '<a href="http://example.org/" title="http://example.org/" rel="external">example.org</a>'), + '<a href="http://example.org/" title="http://example.org/" rel="nofollow external">example.org</a>'), array('example.co.uk', - '<a href="http://example.co.uk/" title="http://example.co.uk/" rel="external">example.co.uk</a>'), + '<a href="http://example.co.uk/" title="http://example.co.uk/" rel="nofollow external">example.co.uk</a>'), array('www.example.co.uk', - '<a href="http://www.example.co.uk/" title="http://www.example.co.uk/" rel="external">www.example.co.uk</a>'), + '<a href="http://www.example.co.uk/" title="http://www.example.co.uk/" rel="nofollow external">www.example.co.uk</a>'), array('farm1.images.example.co.uk', - '<a href="http://farm1.images.example.co.uk/" title="http://farm1.images.example.co.uk/" rel="external">farm1.images.example.co.uk</a>'), + '<a href="http://farm1.images.example.co.uk/" title="http://farm1.images.example.co.uk/" rel="nofollow external">farm1.images.example.co.uk</a>'), array('example.museum', - '<a href="http://example.museum/" title="http://example.museum/" rel="external">example.museum</a>'), + '<a href="http://example.museum/" title="http://example.museum/" rel="nofollow external">example.museum</a>'), array('example.travel', - '<a href="http://example.travel/" title="http://example.travel/" rel="external">example.travel</a>'), + '<a href="http://example.travel/" title="http://example.travel/" rel="nofollow external">example.travel</a>'), array('example.com.', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.'), array('example.com?', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>?'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>?'), array('example.com!', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>!'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>!'), array('example.com,', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>,'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>,'), array('example.com;', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>;'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>;'), array('example.com:', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>:'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>:'), array('\'example.com\'', - '\'<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>\''), + '\'<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>\''), array('"example.com"', - '"<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>"'), + '"<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>"'), array('example.com', - '<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>'), + '<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>'), array('(example.com)', - '(<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>)'), + '(<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>)'), array('[example.com]', - '[<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>]'), + '[<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>]'), array('<example.com>', - '<<a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>>'), + '<<a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>>'), array('Hey, check out my cool site example.com okay?', - 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a> okay?'), + 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a> okay?'), array('Hey, check out my cool site example.com.I made it.', - 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.I made it.'), + 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.I made it.'), array('Hey, check out my cool site example.com.Funny thing...', - 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.Funny thing...'), + 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.Funny thing...'), array('Hey, check out my cool site example.com.You will love it.', - 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="external">example.com</a>.You will love it.'), + 'Hey, check out my cool site <a href="http://example.com/" title="http://example.com/" rel="nofollow external">example.com</a>.You will love it.'), array('What about parens (e.g. example.com/path/foo/(bar))?', - 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>)?'), + 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>)?'), array('What about parens (e.g. example.com/path/foo/(bar)?', - 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>?'), + 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>?'), array('What about parens (e.g. example.com/path/foo/(bar).)?', - 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>.)?'), + 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" title="http://example.com/path/foo/(bar)" rel="nofollow external">example.com/path/foo/(bar)</a>.)?'), array('What about parens (e.g. example.com/path/(foo,bar)?', - 'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="external">example.com/path/(foo,bar)</a>?'), + 'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" title="http://example.com/path/(foo,bar)" rel="nofollow external">example.com/path/(foo,bar)</a>?'), array('file.ext', 'file.ext'), array('file.html', |