diff options
65 files changed, 818 insertions, 309 deletions
diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php index 9fb4796e..87633f4c 100644 --- a/modules/comment/controllers/comments.php +++ b/modules/comment/controllers/comments.php @@ -39,9 +39,9 @@ class Comments_Controller extends REST_Controller { foreach ($comments as $comment) { $data[] = array( "id" => $comment->id, - "author_name" => p::clean($comment->author_name()), + "author_name" => SafeString::of($comment->author_name()), "created" => $comment->created, - "text" => nl2br(p::purify($comment->text))); + "text" => nl2br(SafeString::purify($comment->text))); } print json_encode($data); break; @@ -126,9 +126,9 @@ class Comments_Controller extends REST_Controller { array("result" => "success", "data" => array( "id" => $comment->id, - "author_name" => p::clean($comment->author_name()), + "author_name" => SafeString::of($comment->author_name()), "created" => $comment->created, - "text" => nl2br(p::purify($comment->text))))); + "text" => nl2br(SafeString::purify($comment->text))))); } else { $view = new Theme_View("comment.html", "fragment"); $view->comment = $comment; diff --git a/modules/comment/helpers/comment_rss.php b/modules/comment/helpers/comment_rss.php index e233de59..4151dcd0 100644 --- a/modules/comment/helpers/comment_rss.php +++ b/modules/comment/helpers/comment_rss.php @@ -23,7 +23,7 @@ class comment_rss_Core { $feeds["comment/newest"] = t("All new comments"); if ($item) { $feeds["comment/item/$item->id"] = - t("Comments on %title", array("title" => p::purify($item->title))); + t("Comments on %title", array("title" => SafeString::purify($item->title))); } return $feeds; } @@ -49,13 +49,13 @@ class comment_rss_Core { $item = $comment->item(); $feed->children[] = new ArrayObject( array("pub_date" => date("D, d M Y H:i:s T", $comment->created), - "text" => nl2br(p::purify($comment->text)), + "text" => nl2br(SafeString::purify($comment->text)), "thumb_url" => $item->thumb_url(), "thumb_height" => $item->thumb_height, "thumb_width" => $item->thumb_width, "item_uri" => url::abs_site("{$item->type}s/$item->id"), - "title" => p::purify($item->title), - "author" => p::clean($comment->author_name())), + "title" => SafeString::purify($item->title), + "author" => SafeString::of($comment->author_name())), ArrayObject::ARRAY_AS_PROPS); } diff --git a/modules/comment/views/admin_block_recent_comments.html.php b/modules/comment/views/admin_block_recent_comments.html.php index 516a8181..2c7a5cf1 100644 --- a/modules/comment/views/admin_block_recent_comments.html.php +++ b/modules/comment/views/admin_block_recent_comments.html.php @@ -4,13 +4,13 @@ <li class="<?= ($i % 2 == 0) ? "gEvenRow" : "gOddRow" ?>"> <img src="<?= $comment->author()->avatar_url(32, $theme->url("images/avatar.jpg", true)) ?>" class="gAvatar" - alt="<?= p::clean($comment->author_name()) ?>" + alt="<?= SafeString::of($comment->author_name()) ?>" width="32" height="32" /> <?= gallery::date_time($comment->created) ?> <?= t('<a href="#">%author_name</a> said <em>%comment_text</em>', - array("author_name" => p::clean($comment->author_name()), - "comment_text" => text::limit_words(nl2br(p::purify($comment->text)), 50))); ?> + array("author_name" => SafeString::of($comment->author_name()), + "comment_text" => text::limit_words(nl2br(SafeString::purify($comment->text)), 50))); ?> </li> <? endforeach ?> </ul> diff --git a/modules/comment/views/admin_comments.html.php b/modules/comment/views/admin_comments.html.php index 03511d91..8b0b4c29 100644 --- a/modules/comment/views/admin_comments.html.php +++ b/modules/comment/views/admin_comments.html.php @@ -108,12 +108,12 @@ <a href="#"> <img src="<?= $comment->author()->avatar_url(40, $theme->url("images/avatar.jpg", true)) ?>" class="gAvatar" - alt="<?= p::clean($comment->author_name()) ?>" + alt="<?= SafeString::of($comment->author_name()) ?>" width="40" height="40" /> </a> - <p><a href="mailto:<?= p::clean($comment->author_email()) ?>" - title="<?= p::clean($comment->author_email()) ?>"> <?= p::clean($comment->author_name()) ?> </a></p> + <p><a href="mailto:<?= SafeString::of($comment->author_email()) ?>" + title="<?= SafeString::of($comment->author_email()) ?>"> <?= SafeString::of($comment->author_name()) ?> </a></p> </td> <td> <div class="right"> @@ -122,7 +122,7 @@ <a href="<?= $item->url() ?>"> <? if ($item->has_thumb()): ?> <img src="<?= $item->thumb_url() ?>" - alt="<?= p::purify($item->title) ?>" + alt="<?= SafeString::purify($item->title) ?>" <?= photo::img_dimensions($item->thumb_width, $item->thumb_height, 75) ?> /> <? else: ?> @@ -132,7 +132,7 @@ </div> </div> <p><?= gallery::date($comment->created) ?></p> - <?= nl2br(p::purify($comment->text)) ?> + <?= nl2br(SafeString::purify($comment->text)) ?> </td> <td> <ul class="gButtonSetVertical"> diff --git a/modules/comment/views/comment.html.php b/modules/comment/views/comment.html.php index 3d17411c..31bb7f4d 100644 --- a/modules/comment/views/comment.html.php +++ b/modules/comment/views/comment.html.php @@ -4,15 +4,15 @@ <a href="#"> <img src="<?= $comment->author()->avatar_url(40, $theme->url("images/avatar.jpg", true)) ?>" class="gAvatar" - alt="<?= p::clean($comment->author_name()) ?>" + alt="<?= SafeString::of($comment->author_name()) ?>" width="40" height="40" /> </a> <?= t("on %date_time, %author_name said", array("date_time" => gallery::date_time($comment->created), - "author_name" => p::clean($comment->author_name()))) ?> + "author_name" => SafeString::of($comment->author_name()))) ?> </p> <div> - <?= nl2br(p::purify($comment->text)) ?> + <?= nl2br(SafeString::purify($comment->text)) ?> </div> </li> diff --git a/modules/comment/views/comment.mrss.php b/modules/comment/views/comment.mrss.php index 2b5b13c1..ae7762d9 100644 --- a/modules/comment/views/comment.mrss.php +++ b/modules/comment/views/comment.mrss.php @@ -6,9 +6,9 @@ xmlns:fh="http://purl.org/syndication/history/1.0"> <channel> <generator>Gallery 3</generator> - <title><?= p::clean($feed->title) ?></title> + <title><?= SafeString::of($feed->title) ?></title> <link><?= $feed->uri ?></link> - <description><?= p::clean($feed->description) ?></description> + <description><?= SafeString::of($feed->description) ?></description> <language>en-us</language> <atom:link rel="self" href="<?= $feed->uri ?>" type="application/rss+xml" /> <fh:complete/> @@ -22,14 +22,14 @@ <lastBuildDate><?= $pub_date ?></lastBuildDate> <? foreach ($feed->children as $child): ?> <item> - <title><?= p::purify($child->title) ?></title> - <link><?= p::clean($child->item_uri) ?></link> - <author><?= p::clean($child->author) ?></author> + <title><?= SafeString::purify($child->title) ?></title> + <link><?= SafeString::of($child->item_uri) ?></link> + <author><?= SafeString::of($child->author) ?></author> <guid isPermaLink="true"><?= $child->item_uri ?></guid> <pubDate><?= $child->pub_date ?></pubDate> <content:encoded> <![CDATA[ - <p><?= nl2br(p::purify($child->text)) ?></p> + <p><?= nl2br(SafeString::purify($child->text)) ?></p> <p> <img alt="" src="<?= $child->thumb_url ?>" height="<?= $child->thumb_height ?>" width="<?= $child->thumb_width ?>" /> diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index 6dce9971..9eac0502 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -18,16 +18,16 @@ <a href="#"> <img src="<?= $comment->author()->avatar_url(40, $theme->url("images/avatar.jpg", true)) ?>" class="gAvatar" - alt="<?= p::clean($comment->author_name()) ?>" + alt="<?= SafeString::of($comment->author_name()) ?>" width="40" height="40" /> </a> <?= t('on %date <a href="#">%name</a> said', array("date" => date("Y-M-d H:i:s", $comment->created), - "name" => p::clean($comment->author_name()))); ?> + "name" => SafeString::of($comment->author_name()))); ?> </p> <div> - <?= nl2br(p::purify($comment->text)) ?> + <?= nl2br(SafeString::purify($comment->text)) ?> </div> </li> <? endforeach ?> diff --git a/modules/digibug/controllers/digibug.php b/modules/digibug/controllers/digibug.php index e0f4b6bf..509a8b70 100644 --- a/modules/digibug/controllers/digibug.php +++ b/modules/digibug/controllers/digibug.php @@ -50,7 +50,7 @@ class Digibug_Controller extends Controller { "image_width_1" => $item->width, "thumb_height_1" => $item->thumb_height, "thumb_width_1" => $item->thumb_width, - "title_1" => p::purify($item->title)); + "title_1" => SafeString::purify($item->title)); print $v; } diff --git a/modules/exif/views/exif_dialog.html.php b/modules/exif/views/exif_dialog.html.php index 6494b2b0..a981ca09 100644 --- a/modules/exif/views/exif_dialog.html.php +++ b/modules/exif/views/exif_dialog.html.php @@ -14,14 +14,14 @@ <?= $details[$i]["caption"] ?> </td> <td class="gOdd"> - <?= p::clean($details[$i]["value"]) ?> + <?= SafeString::of($details[$i]["value"]) ?> </td> <? if (!empty($details[++$i])): ?> <td class="gEven"> <?= $details[$i]["caption"] ?> </td> <td class="gOdd"> - <?= p::clean($details[$i]["value"]) ?> + <?= SafeString::of($details[$i]["value"]) ?> </td> <? else: ?> <td class="gEven"></td><td class="gOdd"></td> diff --git a/modules/g2_import/helpers/g2_import.php b/modules/g2_import/helpers/g2_import.php index 436cef52..a01ca1db 100644 --- a/modules/g2_import/helpers/g2_import.php +++ b/modules/g2_import/helpers/g2_import.php @@ -590,7 +590,7 @@ class g2_import_Core { self::map($g2_comment->getId(), $comment->id); return t("Imported comment '%comment' for item with id: %id", array("id" => $comment->item_id, - "comment" => text::limit_words(nl2br(p::purify($comment->text)), 50))); + "comment" => text::limit_words(nl2br(SafeString::purify($comment->text)), 50))); } /** diff --git a/modules/gallery/controllers/admin_advanced_settings.php b/modules/gallery/controllers/admin_advanced_settings.php index 64007fdb..d727b654 100644 --- a/modules/gallery/controllers/admin_advanced_settings.php +++ b/modules/gallery/controllers/admin_advanced_settings.php @@ -46,7 +46,7 @@ class Admin_Advanced_Settings_Controller extends Admin_Controller { module::set_var($module_name, $var_name, Input::instance()->post("value")); message::success( t("Saved value for %var (%module_name)", - array("var" => p::clean($var_name), "module_name" => $module_name))); + array("var" => SafeString::of($var_name), "module_name" => $module_name))); print json_encode(array("result" => "success")); } diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index cdfa823d..ec3eb426 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -112,7 +112,7 @@ class Albums_Controller extends Items_Controller { log::success("content", "Created an album", html::anchor("albums/$new_album->id", "view album")); message::success( - t("Created album %album_title", array("album_title" => p::clean($new_album->title)))); + t("Created album %album_title", array("album_title" => $new_album->title))); print json_encode( array("result" => "success", @@ -145,7 +145,7 @@ class Albums_Controller extends Items_Controller { log::success("content", "Added a photo", html::anchor("photos/$photo->id", "view photo")); message::success( - t("Added photo %photo_title", array("photo_title" => p::clean($photo->title)))); + t("Added photo %photo_title", array("photo_title" => $photo->title))); print json_encode( array("result" => "success", @@ -194,7 +194,7 @@ class Albums_Controller extends Items_Controller { log::success("content", "Updated album", "<a href=\"albums/$album->id\">view</a>"); message::success( - t("Saved album %album_title", array("album_title" => p::clean($album->title)))); + t("Saved album %album_title", array("album_title" => $album->title))); print json_encode( array("result" => "success", diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php index c8227d74..09b16759 100644 --- a/modules/gallery/controllers/movies.php +++ b/modules/gallery/controllers/movies.php @@ -93,7 +93,7 @@ class Movies_Controller extends Items_Controller { log::success("content", "Updated photo", "<a href=\"photos/$photo->id\">view</a>"); message::success( - t("Saved photo %photo_title", array("photo_title" => p::clean($photo->title)))); + t("Saved photo %photo_title", array("photo_title" => $photo->title))); print json_encode( array("result" => "success", diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php index 8ee24da8..3447b4c6 100644 --- a/modules/gallery/controllers/photos.php +++ b/modules/gallery/controllers/photos.php @@ -86,7 +86,7 @@ class Photos_Controller extends Items_Controller { log::success("content", "Updated photo", "<a href=\"photos/$photo->id\">view</a>"); message::success( - t("Saved photo %photo_title", array("photo_title" => p::clean($photo->title)))); + t("Saved photo %photo_title", array("photo_title" => $photo->title))); print json_encode( array("result" => "success", diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index 82176e02..8fddb563 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -75,7 +75,7 @@ class Quick_Controller extends Controller { access::required("view", $item->parent()); access::required("edit", $item->parent()); - $msg = t("Made <b>%title</b> this album's cover", array("title" => p::purify($item->title))); + $msg = t("Made <b>%title</b> this album's cover", array("title" => SafeString::purify($item->title))); item::make_album_cover($item); message::success($msg); @@ -91,10 +91,10 @@ class Quick_Controller extends Controller { if ($item->is_album()) { print t( "Delete the album <b>%title</b>? All photos and movies in the album will also be deleted.", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } else { print t("Are you sure you want to delete <b>%title</b>?", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } $form = item::get_delete_form($item); @@ -108,9 +108,9 @@ class Quick_Controller extends Controller { access::required("edit", $item); if ($item->is_album()) { - $msg = t("Deleted album <b>%title</b>", array("title" => p::purify($item->title))); + $msg = t("Deleted album <b>%title</b>", array("title" => SafeString::purify($item->title))); } else { - $msg = t("Deleted photo <b>%title</b>", array("title" => p::purify($item->title))); + $msg = t("Deleted photo <b>%title</b>", array("title" => SafeString::purify($item->title))); } $parent = $item->parent(); diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php index c4967c52..6092a9d8 100644 --- a/modules/gallery/helpers/MY_url.php +++ b/modules/gallery/helpers/MY_url.php @@ -30,7 +30,8 @@ class url extends url_Core { if ($parts[0] == "albums" || $parts[0] == "photos") { $uri = model_cache::get("item", $parts[1])->relative_path(); } - return parent::site($uri . $query, $protocol); + $url = parent::site($uri . $query, $protocol); + return SafeString::of_safe_html($url); } static function parse_url() { @@ -99,4 +100,25 @@ class url extends url_Core { static function abs_current($qs=false) { return self::abs_site(url::current($qs)); } + + public static function base($index=false, $protocol=false) { + $url = parent::base($index, $protocol); + return SafeString::of_safe_html($url); + } + + public static function current($qs=false) { + $url = parent::current($qs); + return SafeString::of_safe_html($url); + } + + public static function file($file, $index=false) { + $url = parent::file($file, $index); + return SafeString::of_safe_html($url); + } + + public static function merge(array $arguments) { + $url = parent::merge($arguments); + return SafeString::of_safe_html($url); + } + } diff --git a/modules/gallery/helpers/gallery_rss.php b/modules/gallery/helpers/gallery_rss.php index 8e887368..affb3101 100644 --- a/modules/gallery/helpers/gallery_rss.php +++ b/modules/gallery/helpers/gallery_rss.php @@ -53,9 +53,9 @@ class gallery_rss_Core { ->descendants($limit, $offset, array("type" => "photo")); $feed->max_pages = ceil( $item->viewable()->descendants_count(array("type" => "photo")) / $limit); - $feed->title = p::purify($item->title); + $feed->title = SafeString::purify($item->title); $feed->link = url::abs_site("albums/{$item->id}"); - $feed->description = nl2br(p::purify($item->description)); + $feed->description = nl2br(SafeString::purify($item->description)); return $feed; } diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 9edc3acd..8c0e8aa8 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -64,10 +64,10 @@ class gallery_task_Core { if (!$success) { $ignored[$item->id] = 1; $errors[] = t("Unable to rebuild images for '%title'", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } else { $errors[] = t("Successfully rebuilt images for '%title'", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } } diff --git a/modules/gallery/helpers/p.php b/modules/gallery/helpers/p.php deleted file mode 100644 index 862c769b..00000000 --- a/modules/gallery/helpers/p.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php defined("SYSPATH") or die("No direct script access."); -/** - * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2009 Bharat Mediratta - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. - */ -class p_Core { - private static $_purifier = null; - static function clean($dirty_html) { - return html::specialchars($dirty_html); - } - - static function purify($dirty_html) { - if (empty(self::$_purifier)) { - require_once(dirname(__file__) . "/../lib/HTMLPurifier/HTMLPurifier.auto.php"); - $config = HTMLPurifier_Config::createDefault(); - foreach (Kohana::config('purifier') as $category => $key_value) { - foreach ($key_value as $key => $value) { - $config->set("$category.$key", $value); - } - } - self::$_purifier = new HTMLPurifier($config); - } - return self::$_purifier->purify($dirty_html); - } -} diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php index d0531b9a..c3336052 100644 --- a/modules/gallery/libraries/I18n.php +++ b/modules/gallery/libraries/I18n.php @@ -89,6 +89,12 @@ class I18n_Core { /** * Translates a localizable message. + * + * Security: + * The returned string is safe for use in HTML (it contains a safe subset of HTML and + * interpolation parameters are converted to HTML entities). + * For use in JavaScript, please call ->for_js() on it. + * * @param $message String|array The message to be translated. E.g. "Hello world" * or array("one" => "One album", "other" => "%count albums") * @param $options array (optional) Options array for key value pairs which are used @@ -115,7 +121,7 @@ class I18n_Core { $entry = $this->interpolate($locale, $entry, $values); - return $entry; + return SafeString::of_safe_html($entry); } private function lookup($locale, $message) { @@ -184,17 +190,19 @@ class I18n_Core { return is_array($message); } - private function interpolate($locale, $string, $values) { + private function interpolate($locale, $string, $key_values) { // TODO: Handle locale specific number formatting. // Replace x_y before replacing x. - krsort($values, SORT_STRING); + krsort($key_values, SORT_STRING); $keys = array(); - foreach (array_keys($values) as $key) { + $values = array(); + foreach ($key_values as $key => $value) { $keys[] = "%$key"; + $values[] = new SafeString($value); } - return str_replace($keys, array_values($values), $string); + return str_replace($keys, $values, $string); } private function pluralize($locale, $entry, $count) { @@ -419,4 +427,4 @@ class I18n_Core { return $count == 1 ? 'one' : 'other'; } } -}
\ No newline at end of file +} diff --git a/modules/gallery/libraries/MY_ORM.php b/modules/gallery/libraries/MY_ORM.php index de8adc1d..2c9ad1d7 100644 --- a/modules/gallery/libraries/MY_ORM.php +++ b/modules/gallery/libraries/MY_ORM.php @@ -43,6 +43,10 @@ class ORM extends ORM_Core { $this->original = clone $this; } + if ($value instanceof SafeString) { + $value = $value->unescaped(); + } + return parent::__set($column, $value); } diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php new file mode 100644 index 00000000..9614a213 --- /dev/null +++ b/modules/gallery/libraries/SafeString.php @@ -0,0 +1,177 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * Safe string representation (regarding security - cross site scripting). + */ +class SafeString_Core { + private $_raw_string; + protected $_is_safe_html = false; + protected $_is_purified_html = false; + + private static $_purifier = null; + + /** Constructor */ + function __construct($string) { + if ($string instanceof SafeString) { + $this->_is_safe_html = $string->_is_safe_html; + $this->_is_purified_html = $string->_is_purified_html; + $string = $string->unescaped(); + } + $this->_raw_string = (string) $string; + } + + /** + * Factory method returning a new SafeString instance for the given string. + */ + static function of($string) { + return new SafeString($string); + } + + /** + * Factory method returning a new SafeString instance after HTML purifying + * the given string. + */ + static function purify($string) { + if ($string instanceof SafeString) { + $string = $string->unescaped(); + } + $safe_string = self::of_safe_html(self::_purify_for_html($string)); + $safe_string->_is_purified_html = true; + return $safe_string; + } + + /** + * Factory method returning a new SafeString instance which won't HTML escape. + */ + static function of_safe_html($string) { + $safe_string = new SafeString($string); + $safe_string->_is_safe_html = true; + return $safe_string; + } + + /** + * Safe for use in HTML. + * @see #for_html() + */ + function __toString() { + if ($this->_is_safe_html) { + return $this->_raw_string; + } else { + return self::_escape_for_html($this->_raw_string); + } + } + + /** + * Safe for use in HTML. + * + * Example:<pre> + * <div><?= $php_var ?> + * </pre> + * @return the string escaped for use in HTML. + */ + function for_html() { + return $this; + } + + /** + * Safe for use in JavaScript. + * + * Example:<pre> + * <script type="text/javascript>" + * var some_js_var = "<?= $php_var->for_js() ?>"; + * </script> + * </pre> + * @return the string escaped for use in JavaScript. + */ + function for_js() { + return self::_escape_for_js($this->_raw_string); + } + + /** + * Safe for use in HTML element attributes. + * + * Assumes that the HTML element attribute is already + * delimited by single or double quotes + * + * Example:<pre> + * <a title="<?= $php_var->for_html_attr() ?>">; + * </script> + * </pre> + * @return the string escaped for use in HTML attributes. + */ + function for_html_attr() { + $string = (string) $this->for_html(); + return strtr($string, + array("'"=>"'", + '"'=>'"')); + } + + /** + * Safe for use HTML (purified HTML) + * + * Example:<pre> + * <div><?= $php_var->purified_html() ?> + * </pre> + * @return the string escaped for use in HTML. + */ + function purified_html() { + if ($this->_is_purified_html) { + return $this; + } else { + return self::purify($this); + } + } + + /** + * Returns the raw, unsafe string. Do not use lightly. + */ + function unescaped() { + return $this->_raw_string; + } + + // Escapes special HTML chars ("<", ">", "&", etc.) to HTML entities. + private static function _escape_for_html($dirty_html) { + return html::specialchars($dirty_html); + } + + // Escapes special chars (quotes, backslash, etc.) with a backslash sequence. + private static function _escape_for_js($string) { + // From Smarty plugins/modifier.escape.php + // Might want to be stricter here. + return strtr($string, + array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n','</'=>'<\/')); + } + + // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. + private static function _purify_for_html($dirty_html) { + if (empty(self::$_purifier)) { + require_once(dirname(__file__) . "/../lib/HTMLPurifier/HTMLPurifier.auto.php"); + $config = HTMLPurifier_Config::createDefault(); + foreach (Kohana::config('purifier') as $category => $key_value) { + foreach ($key_value as $key => $value) { + $config->set("$category.$key", $value); + } + } + self::$_purifier = new HTMLPurifier($config); + } + return self::$_purifier->purify($dirty_html); + } +} diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php new file mode 100644 index 00000000..0fc7f6f3 --- /dev/null +++ b/modules/gallery/tests/SafeString_Test.php @@ -0,0 +1,121 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class SafeString_Test extends Unit_Test_Case { + public function toString_escapes_for_html_test() { + $safe_string = new SafeString("hello <p>world</p>"); + $this->assert_equal("hello <p>world</p>", + $safe_string); + } + + public function toString_for_safe_string_test() { + $safe_string = SafeString::of_safe_html("hello <p>world</p>"); + $this->assert_equal("hello <p>world</p>", + $safe_string); + } + + public function for_html_test() { + $safe_string = new SafeString("hello <p>world</p>"); + $this->assert_equal("hello <p>world</p>", + $safe_string->for_html()); + } + + public function safestring_of_safestring_test() { + $safe_string = new SafeString("hello <p>world</p>"); + $safe_string_2 = new SafeString($safe_string); + $this->assert_true($safe_string_2 instanceof SafeString); + $raw_string = $safe_string_2->unescaped(); + $this->assert_false(is_object($raw_string)); + $this->assert_equal("hello <p>world</p>", $raw_string); + $this->assert_equal("hello <p>world</p>", $safe_string_2); + } + + public function for_js_test() { + $safe_string = new SafeString('"<em>Foo</em>\'s bar"'); + $js_string = $safe_string->for_js(); + $this->assert_equal('\\"<em>Foo<\\/em>\\\'s bar\\"', + $js_string); + } + + public function for_html_attr_test() { + $safe_string = new SafeString('"<em>Foo</em>\'s bar"'); + $attr_string = $safe_string->for_html_attr(); + $this->assert_equal('"<em>Foo</em>'s bar"', + $attr_string); + } + + public function for_html_attr_with_safe_html_test() { + $safe_string = SafeString::of_safe_html('"<em>Foo</em>\'s bar"'); + $attr_string = $safe_string->for_html_attr(); + $this->assert_equal('"<em>Foo</em>'s bar"', + $attr_string); + } + + public function string_safestring_equality_test() { + $safe_string = new SafeString("hello <p>world</p>"); + $this->assert_equal("hello <p>world</p>", + $safe_string->unescaped()); + $escaped_string = "hello <p>world</p>"; + $this->assert_equal($escaped_string, $safe_string); + + $this->assert_true($escaped_string == $safe_string); + $this->assert_false($escaped_string === $safe_string); + $this->assert_false("meow" == $safe_string); + } + + public function of_test() { + $safe_string = SafeString::of("hello <p>world</p>"); + $this->assert_equal("hello <p>world</p>", $safe_string->unescaped()); + } + + public function of_safe_html_test() { + $safe_string = SafeString::of_safe_html("hello <p>world</p>"); + $this->assert_equal("hello <p>world</p>", $safe_string->for_html()); + } + + public function purify_test() { + $safe_string = SafeString::purify("hello <p >world</p>"); + $this->assert_equal("hello <p>world</p>", $safe_string); + } + + public function of_fluid_api_test() { + $escaped_string = SafeString::of("Foo's bar")->for_js(); + $this->assert_equal("Foo\\'s bar", $escaped_string); + } + + public function safestring_of_safestring_preserves_safe_status_test() { + $safe_string = SafeString::of_safe_html("hello's <p>world</p>"); + $safe_string_2 = new SafeString($safe_string); + $this->assert_equal("hello's <p>world</p>", $safe_string_2); + $this->assert_equal("hello\\'s <p>world<\\/p>", $safe_string_2->for_js()); + } + + public function safestring_of_safestring_preserves_html_safe_status_test() { + $safe_string = SafeString::of_safe_html("hello's <p>world</p>"); + $safe_string_2 = new SafeString($safe_string); + $this->assert_equal("hello's <p>world</p>", $safe_string_2); + $this->assert_equal("hello\\'s <p>world<\\/p>", $safe_string_2->for_js()); + } + + public function safestring_of_safestring_safe_status_override_test() { + $safe_string = new SafeString("hello <p>world</p>"); + $safe_string_2 = SafeString::of_safe_html($safe_string); + $this->assert_equal("hello <p>world</p>", $safe_string_2); + } +} diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 9bde11dc..690dc760 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -19,87 +19,304 @@ */ class Xss_Security_Test extends Unit_Test_Case { public function find_unescaped_variables_in_views_test() { + $found = array(); foreach (glob("*/*/views/*.php") as $view) { - $expr = null; - $level = 0; - $php = 0; - $str = null; - $in_p_clean = 0; + // List of all tokens without whitespace, simplifying parsing. + $tokens = array(); foreach (token_get_all(file_get_contents($view)) as $token) { - if (false /* useful for debugging */) { - if (is_array($token)) { - printf("[$str] [$in_p_clean] %-15s %s\n", token_name($token[0]), $token[1]); - } else { - printf("[$str] [$in_p_clean] %-15s %s\n", "<char>", $token); - } - } - - // If we find a "(" after a "p::clean" then start counting levels of parens and assume - // that we're inside a p::clean() call until we find the matching close paren. - if ($token[0] == "(" && ($str == "p::clean" || $str == "p::purify")) { - $in_p_clean = 1; - } else if ($token[0] == "(" && $in_p_clean) { - $in_p_clean++; - } else if ($token[0] == ")" && $in_p_clean) { - $in_p_clean--; - } - - // Concatenate runs of strings for convenience, which we use above to figure out if we're - // inside a p::clean() call or not - if ($token[0] == T_STRING || $token[0] == T_DOUBLE_COLON) { - $str .= $token[1]; - } else { - $str = null; - } - - // Scan for any occurrences of < ? = $variable ? > and store it in $expr - if ($token[0] == T_OPEN_TAG_WITH_ECHO) { - $php++; - } else if ($php && $token[0] == T_CLOSE_TAG) { - $php--; - } else if ($php && $token[0] == T_VARIABLE) { - if (!$expr) { - $entry = array($token[2], $in_p_clean); - } - $expr .= $token[1]; - } else if ($expr) { - if ($token[0] == T_OBJECT_OPERATOR) { - $expr .= $token[1]; - } else if ($token[0] == T_STRING) { - $expr .= $token[1]; - } else if ($token == "(") { - $expr .= $token; - $level++; - } else if ($level > 0 && $token == ")") { - $expr .= $token; - $level--; - } else if ($level > 0) { - $expr .= is_array($token) ? $token[1] : $token; - } else { - $entry[] = $expr; - $found[$view][] = $entry; - $expr = null; - $entry = null; - } - } + if (!is_array($token) || ($token[0] != T_WHITESPACE)) { + $tokens[] = $token; + } + } + + $frame = null; + $script_block = 0; + $in_script_block = false; + + for ($token_number = 0; $token_number < count($tokens); $token_number++) { + $token = $tokens[$token_number]; + + // Are we in a <script> ... </script> block? + if (is_array($token) && $token[0] == T_INLINE_HTML) { + $inline_html = $token[1]; + // T_INLINE_HTML blocks can be split. Need to handle the case + // where one token has "<scr" and the next has "ipt" + while (self::_token_matches(array(T_INLINE_HTML), $tokens, $token_number + 1)) { + $token_number++; + $token = $tokens[$token_number]; + $inline_html .= $token[1]; + } + + if ($frame) { + $frame->expr_append($inline_html); + } + + // Note: This approach won't catch <script src="..."> blocks if the src + // URL is generated via < ? = url::site() ? > or some other PHP. + // Assume that all such script blocks with a src URL have an + // empty element body. + // But we'll catch closing tags for such blocks, so don't keep track + // of opening / closing tag count since it would be meaningless. + + // Handle multiple start / end blocks on the same line? + $opening_script_pos = $closing_script_pos = 0; + if (preg_match_all('{</script>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + $last_match = array_pop($matches[0]); + if (is_array($last_match)) { + $closing_script_pos = $last_match[1]; + } else { + $closing_script_pos = $last_match; + } + } + if (preg_match('{<script\b[^>]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + $last_match = array_pop($matches[0]); + if (is_array($last_match)) { + $opening_script_pos = $last_match[1]; + } else { + $opening_script_pos = $last_match; + } + } + if ($opening_script_pos != $closing_script_pos) { + $in_script_block = $opening_script_pos > $closing_script_pos; + } + } + + // Look and report each instance of < ? = ... ? > + if (!is_array($token)) { + // A single char token, e.g: ; ( ) + if ($frame) { + $frame->expr_append($token); + } + } else if ($token[0] == T_OPEN_TAG_WITH_ECHO) { + // No need for a stack here - assume < ? = cannot be nested. + $frame = self::_create_frame($token, $in_script_block); + } else if ($frame && $token[0] == T_CLOSE_TAG) { + // Store the < ? = ... ? > block that just ended here. + $found[$view][] = $frame; + $frame = null; + } else if ($frame && $token[0] == T_VARIABLE) { + $frame->expr_append($token[1]); + } else if ($frame && $token[0] == T_STRING) { + $frame->expr_append($token[1]); + // t() and t2() are special in that they're guaranteed to return a SafeString(). + if (in_array($token[1], array("t", "t2"))) { + if (self::_token_matches("(", $tokens, $token_number + 1)) { + $frame->is_safestring(true); + $frame->expr_append("("); + + $token_number++; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "SafeString") { + // Looking for SafeString::of(... + if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], array("of", "of_safe_html", "purify")) && + self::_token_matches("(", $tokens, $token_number + 3)) { + $frame->is_safestring(true); + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); + + $token_number += 3; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "json_encode") { + if (self::_token_matches("(", $tokens, $token_number + 1)) { + $frame->json_encode_called(true); + $frame->expr_append("("); + + $token_number++; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "url") { + // url methods return a SafeString + if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("site", "current", "base", "file", "abs_site", "abs_current", + "abs_file", "merge")) && + self::_token_matches("(", $tokens, $token_number + 3)) { + $frame->is_safestring(true); + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); + + $token_number += 3; + $token = $tokens[$token_number]; + } + } + } else if ($frame && $token[0] == T_OBJECT_OPERATOR) { + $frame->expr_append($token[1]); + + if (self::_token_matches(array(T_STRING), $tokens, $token_number + 1) && + in_array($tokens[$token_number + 1][1], + array("for_js", "for_html", "purified_html")) && + self::_token_matches("(", $tokens, $token_number + 2)) { + + $method = $tokens[$token_number + 1][1]; + $frame->expr_append("$method("); + + $token_number += 2; + $token = $tokens[$token_number]; + + if ("for_js" == $method) { + $frame->for_js_called(true); + } else if ("for_html" == $method) { + $frame->for_html_called(true); + } else if ("purified_html" == $method) { + $frame->purified_html_called(true); + } + } + } else if ($frame) { + $frame->expr_append($token[1]); + } } } - $canonical = MODPATH . "gallery/tests/xss_data.txt"; + /* + * Generate the report + * + * States for uses of < ? = X ? >: + * DIRTY_JS: + * In <script> block + * X can be anything without calling ->for_js() + * DIRTY: + * Outside <script> block: + * X can be anything without a call to ->for_html() or ->purified_html() + * CLEAN: + * Outside <script> block: + * X = is SafeString (t(), t2(), url::site()) + * X = * and for_html() or purified_html() is called + * Inside <script> block: + * X = * with ->for_js() or json_encode(...) + */ $new = TMPPATH . "xss_data.txt"; $fd = fopen($new, "wb"); ksort($found); - foreach ($found as $view => $entries) { - foreach ($entries as $entry) { - fwrite($fd, - sprintf("%-60s %-3s %-5s %s\n", - $view, $entry[0], $entry[1] ? "" : "DIRTY", $entry[2])); + foreach ($found as $view => $frames) { + foreach ($frames as $frame) { + $state = "DIRTY"; + if ($frame->in_script_block()) { + $state = "DIRTY_JS"; + if ($frame->for_js_called() || $frame->json_encode_called()) { + $state = "CLEAN"; + } + } else { + if ($frame->is_safestring() || $frame->purified_html_called() || $frame->for_html_called()) { + $state = "CLEAN"; + } + } + + if ("CLEAN" == $state) { + // Don't print CLEAN instances - No need to update the golden + // file when adding / moving clean instances. + continue; + } + + fprintf($fd, "%-60s %-3s %-8s %s\n", + $view, $frame->line(), $state, $frame->expr()); } } fclose($fd); + // Compare with the expected report from our golden file. + $canonical = MODPATH . "gallery/tests/xss_data.txt"; exec("diff $canonical $new", $output, $return_value); $this->assert_false( $return_value, "XSS golden file mismatch. Output:\n" . implode("\n", $output) ); } + + private static function _create_frame($token, $in_script_block) { + return new Xss_Security_Test_Frame($token[2], $in_script_block); + } + + private static function _token_matches($expected_token, &$tokens, $token_number) { + if (!isset($tokens[$token_number])) { + return false; + } + + $token = $tokens[$token_number]; + + if (is_array($expected_token)) { + for ($i = 0; $i < count($expected_token); $i++) { + if ($expected_token[$i] != $token[$i]) { + return false; + } + } + return true; + } else { + return $expected_token == $token; + } + } +} + +class Xss_Security_Test_Frame { + private $_expr = ""; + private $_in_script_block = false; + private $_is_safestring = false; + private $_for_js_called = false; + private $_for_html_called = false; + private $_purified_html_called = false; + private $_json_encode_called = false; + private $_line; + + function __construct($line_number, $in_script_block) { + $this->_line = $line_number; + $this->in_script_block($in_script_block); + } + + function expr() { + return $this->_expr; + } + + function expr_append($append_value) { + return $this->_expr .= $append_value; + } + + function in_script_block($new_val=NULL) { + if ($new_val !== NULL) { + $this->_in_script_block = (bool) $new_val; + } + return $this->_in_script_block; + } + + function is_safestring($new_val=NULL) { + if ($new_val !== NULL) { + $this->_is_safestring = (bool) $new_val; + } + return $this->_is_safestring; + } + + function json_encode_called($new_val=NULL) { + if ($new_val !== NULL) { + $this->_json_encode_called = (bool) $new_val; + } + return $this->_json_encode_called; + } + + function for_js_called($new_val=NULL) { + if ($new_val !== NULL) { + $this->_for_js_called = (bool) $new_val; + } + return $this->_for_js_called; + } + + function for_html_called($new_val=NULL) { + if ($new_val !== NULL) { + $this->_for_html_called = (bool) $new_val; + } + return $this->_for_html_called; + } + + function purified_html_called($new_val=NULL) { + if ($new_val !== NULL) { + $this->_purified_html_called = (bool) $new_val; + } + return $this->_purified_html_called; + } + + function line() { + return $this->_line; + } } diff --git a/modules/gallery/views/admin_advanced_settings.html.php b/modules/gallery/views/admin_advanced_settings.html.php index b37c1c73..adc15b91 100644 --- a/modules/gallery/views/admin_advanced_settings.html.php +++ b/modules/gallery/views/admin_advanced_settings.html.php @@ -20,13 +20,13 @@ <? if ($var->module_name == "gallery" && $var->name == "_cache") continue ?> <tr class="setting"> <td> <?= $var->module_name ?> </td> - <td> <?= p::clean($var->name) ?> </td> + <td> <?= SafeString::of($var->name) ?> </td> <td> - <a href="<?= url::site("admin/advanced_settings/edit/$var->module_name/" . p::clean($var->name)) ?>" + <a href="<?= url::site("admin/advanced_settings/edit/$var->module_name/" . SafeString::of($var->name)) ?>" class="gDialogLink" - title="<?= t("Edit %var (%module_name)", array("var" => p::clean($var->name), "module_name" => $var->module_name)) ?>"> + title="<?= t("Edit %var (%module_name)", array("var" => $var->name, "module_name" => $var->module_name)) ?>"> <? if ($var->value): ?> - <?= p::clean($var->value) ?> + <?= SafeString::of($var->value) ?> <? else: ?> <i> <?= t("empty") ?> </i> <? endif ?> diff --git a/modules/gallery/views/admin_block_log_entries.html.php b/modules/gallery/views/admin_block_log_entries.html.php index 44c1657f..b7afb22d 100644 --- a/modules/gallery/views/admin_block_log_entries.html.php +++ b/modules/gallery/views/admin_block_log_entries.html.php @@ -2,7 +2,7 @@ <ul> <? foreach ($entries as $entry): ?> <li class="<?= log::severity_class($entry->severity) ?>" style="direction: ltr"> - <a href="<?= url::site("user/$entry->user_id") ?>"><?= p::clean($entry->user->name) ?></a> + <a href="<?= url::site("user/$entry->user_id") ?>"><?= SafeString::of($entry->user->name) ?></a> <?= gallery::date_time($entry->timestamp) ?> <?= $entry->message ?> <?= $entry->html ?> diff --git a/modules/gallery/views/admin_block_photo_stream.html.php b/modules/gallery/views/admin_block_photo_stream.html.php index 1e1329d1..732bdc38 100644 --- a/modules/gallery/views/admin_block_photo_stream.html.php +++ b/modules/gallery/views/admin_block_photo_stream.html.php @@ -2,9 +2,9 @@ <ul> <? foreach ($photos as $photo): ?> <li class="gItem gPhoto"> - <a href="<?= url::site("photos/$photo->id") ?>" title="<?= p::clean($photo->title) ?>"> + <a href="<?= url::site("photos/$photo->id") ?>" title="<?= SafeString::of($photo->title) ?>"> <img <?= photo::img_dimensions($photo->width, $photo->height, 72) ?> - src="<?= $photo->thumb_url() ?>" alt="<?= p::clean($photo->title) ?>" /> + src="<?= $photo->thumb_url() ?>" alt="<?= SafeString::of($photo->title) ?>" /> </a> </li> <? endforeach ?> diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index 3649ea58..a0a6a19e 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -93,7 +93,7 @@ <?= $task->status ?> </td> <td> - <?= p::clean($task->owner()->name) ?> + <?= SafeString::of($task->owner()->name) ?> </td> <td> <? if ($task->state == "stalled"): ?> diff --git a/modules/gallery/views/admin_maintenance_show_log.html.php b/modules/gallery/views/admin_maintenance_show_log.html.php index 9d850986..209aef03 100644 --- a/modules/gallery/views/admin_maintenance_show_log.html.php +++ b/modules/gallery/views/admin_maintenance_show_log.html.php @@ -12,7 +12,7 @@ appendTo('body').submit().remove(); <div id="gTaskLogDialog"> <h1> <?= $task->name ?> </h1> <div class="gTaskLog"> - <pre><?= p::purify($task->get_log()) ?></pre> + <pre><?= SafeString::purify($task->get_log()) ?></pre> </div> <button id="gCloseButton" class="ui-state-default ui-corner-all" onclick="dismiss()"><?= t("Close") ?></button> <button id="gSaveButton" class="ui-state-default ui-corner-all" onclick="download()"><?= t("Save") ?></button> diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index bfce46f0..b77a1707 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -8,7 +8,7 @@ </p> <p> - <?= t("You're logged in to the <b>%user_name</b> account. The very first thing you should do is to change your password to something that you'll remember.", array("user_name" => p::clean($user->name))) ?> + <?= t("You're logged in to the <b>%user_name</b> account. The very first thing you should do is to change your password to something that you'll remember.", array("user_name" => $user->name)) ?> </p> <p> diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php index 5ee7eca3..520fd79e 100644 --- a/modules/gallery/views/l10n_client.html.php +++ b/modules/gallery/views/l10n_client.html.php @@ -72,8 +72,8 @@ </div> </div> <script type="text/javascript"> - var MSG_TRANSLATE_TEXT = "<?= t("Translate Text") ?>"; - var MSG_CLOSE_X = "<?= t("X") ?>"; + var MSG_TRANSLATE_TEXT = "<?= t("Translate Text")->for_js() ?>"; + var MSG_CLOSE_X = "<?= t("X")->for_js() ?>"; var l10n_client_data = <?= json_encode($string_list) ?>; var plural_forms = <?= json_encode($plural_forms) ?>; </script> diff --git a/modules/gallery/views/move_tree.html.php b/modules/gallery/views/move_tree.html.php index 5f70cf67..7818a42a 100644 --- a/modules/gallery/views/move_tree.html.php +++ b/modules/gallery/views/move_tree.html.php @@ -1,18 +1,18 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <?= $parent->thumb_img(array(), 25); ?> <? if (!access::can("edit", $parent) || $source->is_descendant($parent)): ?> -<a href="javascript:load_tree('<?= $parent->id ?>',1)"> <?= p::clean($parent->title) ?> <?= t("(locked)") ?> </a> +<a href="javascript:load_tree('<?= $parent->id ?>',1)"> <?= SafeString::of($parent->title) ?> <?= t("(locked)") ?> </a> <? else: ?> -<a href="javascript:load_tree('<?= $parent->id ?>',0)"> <?= p::clean($parent->title) ?></a> +<a href="javascript:load_tree('<?= $parent->id ?>',0)"> <?= SafeString::of($parent->title) ?></a> <? endif ?> <ul id="tree_<?= $parent->id ?>"> <? foreach ($children as $child): ?> <li id="node_<?= $child->id ?>" class="node"> <?= $child->thumb_img(array(), 25); ?> <? if (!access::can("edit", $child) || $source->is_descendant($child)): ?> - <a href="javascript:load_tree('<?= $child->id ?>',1)"> <?= p::clean($child->title) ?> <?= t("(locked)") ?></a> + <a href="javascript:load_tree('<?= $child->id ?>',1)"> <?= SafeString::of($child->title) ?> <?= t("(locked)") ?></a> <? else: ?> - <a href="javascript:load_tree('<?= $child->id ?>',0)"> <?= p::clean($child->title) ?> </a> + <a href="javascript:load_tree('<?= $child->id ?>',0)"> <?= SafeString::of($child->title) ?> </a> <? endif ?> </li> <? endforeach ?> diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php index f990896c..90970112 100644 --- a/modules/gallery/views/permissions_browse.html.php +++ b/modules/gallery/views/permissions_browse.html.php @@ -33,21 +33,21 @@ </ul> <? endif ?> - <p>Edit permissions for album:</p> + <p><?= t("Edit permissions for album:") ?></p> <ul class="gBreadcrumbs"> <? foreach ($parents as $parent): ?> <li id="item-<?= $parent->id ?>"> <a href="javascript:show(<?= $parent->id ?>)"> - <?= p::purify($parent->title) ?> + <?= SafeString::purify($parent->title) ?> </a> </li> <? endforeach ?> <li class="active" id="item-<?= $item->id ?>"> <a href="javascript:show(<?= $item->id ?>)"> - <?= p::purify($item->title) ?></li> - </a> - </li> + <?= SafeString::purify($item->title) ?> + </a> + </li> </ul> <div id="gEditPermissionForm"> diff --git a/modules/gallery/views/permissions_form.html.php b/modules/gallery/views/permissions_form.html.php index ee5e3a24..adc0496f 100644 --- a/modules/gallery/views/permissions_form.html.php +++ b/modules/gallery/views/permissions_form.html.php @@ -6,7 +6,7 @@ <tr> <th> </th> <? foreach ($groups as $group): ?> - <th> <?= p::clean($group->name) ?> </th> + <th> <?= SafeString::of($group->name) ?> </th> <? endforeach ?> </tr> diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index 29a0dfe8..1f185780 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -6,7 +6,7 @@ <!-- hack to set the title for the dialog --> <form id="gAddPhotosForm" action="<?= url::site("simple_uploader/finish?csrf=$csrf") ?>"> <fieldset> - <legend> <?= t("Add photos to %album_title", array("album_title" => p::purify($item->title))) ?> </legend> + <legend> <?= t("Add photos to %album_title", array("album_title" => SafeString::purify($item->title))) ?> </legend> </fieldset> </form> @@ -26,9 +26,9 @@ </p> <ul class="gBreadcrumbs"> <? foreach ($item->parents() as $parent): ?> - <li> <?= p::clean($parent->title) ?> </li> + <li> <?= SafeString::of($parent->title) ?> </li> <? endforeach ?> - <li class="active"> <?= p::purify($item->title) ?> </li> + <li class="active"> <?= SafeString::purify($item->title) ?> </li> </ul> <p> @@ -82,27 +82,26 @@ <script type="text/javascript"> var swfu = new SWFUpload({ - flash_url: "<?= url::file("lib/swfupload/swfupload.swf") ?>", - upload_url: "<?= url::site("simple_uploader/add_photo/$item->id") ?>", - post_params: { - "g3sid": "<?= Session::instance()->id() ?>", - "user_agent": "<?= Input::instance()->server("HTTP_USER_AGENT") ?>", - "csrf": "<?= $csrf ?>" - }, - file_size_limit: "<?= ini_get("upload_max_filesize") ? num::convert_to_bytes(ini_get("upload_max_filesize"))."B" : "100MB" ?>", + flash_url: "<?= url::file("lib/swfupload/swfupload.swf")->for_js() ?>", + upload_url: "<?= url::site("simple_uploader/add_photo/$item->id")->for_js() ?>", + post_params: <?= json_encode(array( + "g3sid" => Session::instance()->id(), + "user_agent" => Input::instance()->server("HTTP_USER_AGENT"), + "csrf" => $csrf)) ?>, + file_size_limit: "<?= SafeString::of(ini_get("upload_max_filesize") ? num::convert_to_bytes(ini_get("upload_max_filesize"))."B" : "100MB")->for_js() ?>", file_types: "*.gif;*.jpg;*.jpeg;*.png;*.flv;*.mp4;*.GIF;*.JPG;*.JPEG;*.PNG;*.FLV;*.MP4", - file_types_description: "<?= t("Photos and Movies") ?>", + file_types_description: "<?= t("Photos and Movies")->for_js() ?>", file_upload_limit: 1000, file_queue_limit: 0, custom_settings: { }, debug: false, // Button settings - button_image_url: "<?= url::file("themes/default/images/select-photos-backg.png") ?>", + button_image_url: "<?= url::file("themes/default/images/select-photos-backg.png")->for_js() ?>", button_width: "202", button_height: "45", button_placeholder_id: "gChooseFilesButtonPlaceholder", - button_text: '<span class="swfUploadFont"><?= t("Select photos...") ?></span>', + button_text: <?= json_encode('<span class="swfUploadFont">' . t("Select photos...") . '</span>') ?>, button_text_style: ".swfUploadFont { color: #2E6E9E; font-size: 16px; font-family: Lucida Grande,Lucida Sans,Arial,sans-serif; font-weight: bold; }", button_text_left_padding: 30, button_text_top_padding: 10, @@ -146,13 +145,13 @@ function file_queued(file) { var fp = new File_Progress(file); fp.title.html(file.name); - fp.set_status("pending", "<?= t("Pending...") ?>"); + fp.set_status("pending", "<?= t("Pending...")->for_js() ?>"); // @todo add cancel button to call this.cancelUpload(file.id) } function file_queue_error(file, error_code, message) { if (error_code === SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED) { - alert("<?= t("You have attempted to queue too many files.") ?>"); + alert("<?= t("You have attempted to queue too many files.")->for_js() ?>"); return; } @@ -160,20 +159,20 @@ switch (error_code) { case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT: fp.title.html(file.name); - fp.set_status("error", "<?= t("<strong>File is too big.</strong> A likely error source is a too low value for <em>upload_max_filesize</em> (%upload_max_filesize) in your <em>php.ini</em>.", array("upload_max_filesize" => ini_get("upload_max_filesize"))) ?>"); + fp.set_status("error", "<?= t("<strong>File is too big.</strong> A likely error source is a too low value for <em>upload_max_filesize</em> (%upload_max_filesize) in your <em>php.ini</em>.", array("upload_max_filesize" => ini_get("upload_max_filesize")))->for_js() ?>"); break; case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE: fp.title.html(file.name); - fp.set_status("error", "<?= t("Cannot upload empty files.") ?>"); + fp.set_status("error", "<?= t("Cannot upload empty files.")->for_js() ?>"); break; case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE: fp.title.html(file.name); - fp.set_status("error", "<?= t("Invalid file type.") ?>"); + fp.set_status("error", "<?= t("Invalid file type.")->for_js() ?>"); break; default: if (file !== null) { fp.title.html(file.name); - fp.set_status("error", "<?= t("Unknown error") ?>"); + fp.set_status("error", "<?= t("Unknown error")->for_js() ?>"); } break; } @@ -194,7 +193,7 @@ // no uploadProgress events are called (limitation in the Linux Flash VM). var fp = new File_Progress(file); fp.title.html(file.name); - fp.set_status("uploading", "<?= t("Uploading...") ?>"); + fp.set_status("uploading", "<?= t("Uploading...")->for_js() ?>"); $("#gAddPhotosCanvas").scrollTo(fp.box, 1000); return true; // @todo add cancel button to call this.cancelUpload(file.id) @@ -203,7 +202,7 @@ function upload_progress(file, bytes_loaded, bytes_total) { var percent = Math.ceil((bytes_loaded / bytes_total) * 100); var fp = new File_Progress(file); - fp.set_status("uploading", "<?= t("Uploading...") ?>"); + fp.set_status("uploading", "<?= t("Uploading...")->for_js() ?>"); fp.progress_bar.css("visibility", "visible"); fp.progress_bar.progressbar("value", percent); } @@ -211,42 +210,42 @@ function upload_success(file, serverData) { var fp = new File_Progress(file); fp.progress_bar.progressbar("value", 100); - fp.set_status("complete", "<?= t("Complete.") ?>"); + fp.set_status("complete", "<?= t("Complete.")->for_js() ?>"); } function upload_error(file, error_code, message) { var fp = new File_Progress(file); switch (error_code) { case SWFUpload.UPLOAD_ERROR.HTTP_ERROR: - fp.set_status("error", "<?= t("Upload error: bad image file") ?>"); + fp.set_status("error", "<?= t("Upload error: bad image file")->for_js() ?>"); break; case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED: - fp.set_status("error", "<?= t("Upload failed") ?>"); + fp.set_status("error", "<?= t("Upload failed")->for_js() ?>"); break; case SWFUpload.UPLOAD_ERROR.IO_ERROR: - fp.set_status("error", "<?= t("Server error") ?>"); + fp.set_status("error", "<?= t("Server error")->for_js() ?>"); break; case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR: - fp.set_status("error", "<?= t("Security error") ?>"); + fp.set_status("error", "<?= t("Security error")->for_js() ?>"); break; case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED: - fp.set_status("error", "<?= t("Upload limit exceeded") ?>"); + fp.set_status("error", "<?= t("Upload limit exceeded")->for_js() ?>"); break; case SWFUpload.UPLOAD_ERROR.FILE_VALIDATION_FAILED: - fp.set_status("error", "<?= t("Failed validation. File skipped") ?>"); + fp.set_status("error", "<?= t("Failed validation. File skipped")->for_js() ?>"); break; case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED: // If there aren't any files left (they were all cancelled) disable the cancel button if (this.getStats().files_queued === 0) { $("#gUploadCancel").hide(); } - fp.set_status("error", "<?= t("Cancelled") ?>"); + fp.set_status("error", "<?= t("Cancelled")->for_js() ?>"); break; case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED: - fp.set_status("error", "<?= t("Stopped") ?>"); + fp.set_status("error", "<?= t("Stopped")->for_js() ?>"); break; default: - fp.set_status("error", "<?= t("Unknown error: ") ?>" + error_code); + fp.set_status("error", "<?= t("Unknown error: ")->for_js() ?>" + error_code); break; } } @@ -260,7 +259,7 @@ } function get_completed_status_msg(stats) { - var msg = "<?= t("Upload Queue (completed %completed of %total)", array("completed" => "__COMPLETED__", "total" => "__TOTAL__")) ?>"; + var msg = "<?= t("Upload Queue (completed %completed of %total)", array("completed" => "__COMPLETED__", "total" => "__TOTAL__"))->for_js() ?>"; msg = msg.replace("__COMPLETED__", stats.successful_uploads); msg = msg.replace("__TOTAL__", stats.files_queued + stats.successful_uploads + stats.upload_errors + stats.upload_cancelled + stats.queue_errors); @@ -269,7 +268,7 @@ // This event comes from the Queue Plugin function queue_complete(num_files_uploaded) { - var status_msg = "<?= t("Uploaded: __COUNT__") ?>"; + var status_msg = "<?= t("Uploaded: __COUNT__")->for_js() ?>"; $("#gUploadStatus").html(status_msg.replace("__COUNT__", num_files_uploaded)); } </script> diff --git a/modules/info/views/info_block.html.php b/modules/info/views/info_block.html.php index 3c668168..bfaaee99 100644 --- a/modules/info/views/info_block.html.php +++ b/modules/info/views/info_block.html.php @@ -2,18 +2,18 @@ <ul class="gMetadata"> <li> <strong class="caption"><?= t("Title:") ?></strong> - <?= p::purify($item->title) ?> + <?= SafeString::purify($item->title) ?> </li> <? if ($item->description): ?> <li> <strong class="caption"><?= t("Description:") ?></strong> - <?= nl2br(p::purify($item->description)) ?> + <?= nl2br(SafeString::purify($item->description)) ?> </li> <? endif ?> <? if (!$item->is_album()): ?> <li> <strong class="caption"><?= t("File name:") ?></strong> - <?= p::clean($item->name) ?> + <?= SafeString::of($item->name) ?> </li> <? endif ?> <? if ($item->captured): ?> @@ -26,9 +26,9 @@ <li> <strong class="caption"><?= t("Owner:") ?></strong> <? if ($item->owner->url): ?> - <a href="<?= $item->owner->url ?>"><?= p::clean($item->owner->display_name()) ?></a> + <a href="<?= $item->owner->url ?>"><?= SafeString::of($item->owner->display_name()) ?></a> <? else: ?> - <?= p::clean($item->owner->display_name()) ?> + <?= SafeString::of($item->owner->display_name()) ?> <? endif ?> </li> <? endif ?> diff --git a/modules/notification/views/comment_published.html.php b/modules/notification/views/comment_published.html.php index 4a56cdad..02daf921 100644 --- a/modules/notification/views/comment_published.html.php +++ b/modules/notification/views/comment_published.html.php @@ -1,26 +1,26 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <html> <head> - <title><?= p::clean($subject) ?> </title> + <title><?= SafeString::of($subject) ?> </title> </head> <body> - <h2><?= p::clean($subject) ?></h2> + <h2><?= SafeString::of($subject) ?></h2> <table> <tr> <td><?= t("Comment:") ?></td> - <td><?= nl2br(p::purify($comment->text)) ?></td> + <td><?= nl2br(SafeString::purify($comment->text)) ?></td> </tr> <tr> <td><?= t("Author Name:") ?></td> - <td><?= p::clean($comment->author_name()) ?></td> + <td><?= SafeString::of($comment->author_name()) ?></td> </tr> <tr> <td><?= t("Author Email:") ?></td> - <td><?= p::clean($comment->author_email()) ?></td> + <td><?= SafeString::of($comment->author_email()) ?></td> </tr> <tr> <td><?= t("Author URL:") ?></td> - <td><?= p::clean($comment->author_url()) ?></td> + <td><?= SafeString::of($comment->author_url()) ?></td> </tr> <tr> <td><?= t("Url:") ?></td> diff --git a/modules/notification/views/item_added.html.php b/modules/notification/views/item_added.html.php index 86724927..70b8fca4 100644 --- a/modules/notification/views/item_added.html.php +++ b/modules/notification/views/item_added.html.php @@ -1,14 +1,14 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <html> <head> - <title><?= p::clean($subject) ?> </title> + <title><?= SafeString::of($subject) ?> </title> </head> <body> - <h2><?= p::clean($subject) ?></h2> + <h2><?= SafeString::of($subject) ?></h2> <table> <tr> <td><?= t("Title:") ?></td> - <td><?= p::purify($item->title) ?></td> + <td><?= SafeString::purify($item->title) ?></td> </tr> <tr> <td><?= t("Url:") ?></td> @@ -21,7 +21,7 @@ <? if ($item->description): ?> <tr> <td><?= t("Description:") ?></td> - <td><?= nl2br(p::purify($item->description)) ?></td> + <td><?= nl2br(SafeString::purify($item->description)) ?></td> </tr> <? endif ?> </table> diff --git a/modules/notification/views/item_deleted.html.php b/modules/notification/views/item_deleted.html.php index 92215211..e04fc71b 100644 --- a/modules/notification/views/item_deleted.html.php +++ b/modules/notification/views/item_deleted.html.php @@ -1,15 +1,15 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <html> <head> - <title><?= p::clean($subject) ?> </title> + <title><?= SafeString::of($subject) ?> </title> </head> <body> - <h2><?= p::clean($subject) ?></h2> + <h2><?= SafeString::of($subject) ?></h2> <table> <tr> <td colspan="2"> <?= t("To view the changed album %title use the link below.", - array("title" => p::purify($item->parent()->title))) ?> + array("title" => SafeString::purify($item->parent()->title))) ?> </td> </tr> <tr> diff --git a/modules/notification/views/item_updated.html.php b/modules/notification/views/item_updated.html.php index 39f9113b..c3a4f795 100644 --- a/modules/notification/views/item_updated.html.php +++ b/modules/notification/views/item_updated.html.php @@ -1,18 +1,18 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <html> <head> - <title><?= p::clean($subject) ?> </title> + <title><?= SafeString::of($subject) ?> </title> </head> <body> - <h2> <?= p::clean($subject) ?> </h2> + <h2> <?= SafeString::of($subject) ?> </h2> <table> <tr> <? if ($item->original("title") != $item->title): ?> <td><?= t("New Title:") ?></td> - <td><?= p::clean($item->title) ?></td> + <td><?= SafeString::of($item->title) ?></td> <? else: ?> <td><?= t("Title:") ?></td> - <td><?= p::clean($item->title) ?></td> + <td><?= SafeString::of($item->title) ?></td> <? endif ?> </tr> <tr> @@ -22,12 +22,12 @@ <? if ($item->original("description") != $item->description): ?> <tr> <td><?= t("New Description:") ?></td> - <td><?= p::clean($item->description) ?></td> + <td><?= SafeString::of($item->description) ?></td> </tr> <? elseif (!empty($item->description)): ?> <tr> <td><?= t("Description:") ?></td> - <td><?= p::clean($item->description) ?></td> + <td><?= SafeString::of($item->description) ?></td> </tr> <? endif ?> </table> diff --git a/modules/rss/views/feed.mrss.php b/modules/rss/views/feed.mrss.php index 447179a5..7298b7f4 100644 --- a/modules/rss/views/feed.mrss.php +++ b/modules/rss/views/feed.mrss.php @@ -6,9 +6,9 @@ xmlns:fh="http://purl.org/syndication/history/1.0"> <channel> <generator>gallery3</generator> - <title><?= p::clean($feed->title) ?></title> + <title><?= SafeString::of($feed->title) ?></title> <link><?= $feed->uri ?></link> - <description><?= p::clean($feed->description) ?></description> + <description><?= SafeString::of($feed->description) ?></description> <language>en-us</language> <atom:link rel="self" href="<?= $feed->uri ?>" type="application/rss+xml" /> <fh:complete/> @@ -22,25 +22,25 @@ <lastBuildDate><?= $pub_date ?></lastBuildDate> <? foreach ($feed->children as $child): ?> <item> - <title><?= p::clean($child->title) ?></title> + <title><?= SafeString::of($child->title) ?></title> <link><?= url::abs_site("{$child->type}s/{$child->id}") ?></link> <guid isPermaLink="true"><?= url::abs_site("{$child->type}s/{$child->id}") ?></guid> <pubDate><?= date("D, d M Y H:i:s T", $child->created); ?></pubDate> <content:encoded> <![CDATA[ - <span><?= p::clean($child->description) ?></span> + <span><?= SafeString::of($child->description) ?></span> <p> <? if ($child->type == "photo" || $child->type == "album"): ?> <img alt="" src="<?= $child->resize_url(true) ?>" - title="<?= p::clean($child->title) ?>" + title="<?= SafeString::of($child->title) ?>" height="<?= $child->resize_height ?>" width="<?= $child->resize_width ?>" /><br /> <? else: ?> <a href="<?= url::abs_site("{$child->type}s/{$child->id}") ?>"> <img alt="" src="<?= $child->thumb_url(true) ?>" - title="<?= p::clean($child->title) ?>" + title="<?= SafeString::of($child->title) ?>" height="<?= $child->thumb_height ?>" width="<?= $child->thumb_width ?>" /></a><br /> <? endif ?> - <?= p::clean($child->description) ?> + <?= SafeString::of($child->description) ?> </p> ]]> </content:encoded> diff --git a/modules/search/views/search.html.php b/modules/search/views/search.html.php index 6a222ef1..e5c7b4a6 100644 --- a/modules/search/views/search.html.php +++ b/modules/search/views/search.html.php @@ -8,10 +8,10 @@ <ul> <li> <label for="q"><?= t("Search the gallery") ?></label> - <input name="q" id="q" type="text" value="<?= p::clean($q) ?>"/> + <input name="q" id="q" type="text" value="<?= SafeString::of($q)->for_html_attr() ?>"/> </li> <li> - <input type="submit" value="<?= t("Search") ?>" /> + <input type="submit" value="<?= t("Search")->for_html_attr() ?>" /> </li> </ul> </fieldset> @@ -31,10 +31,10 @@ <a href="<?= url::site("items/$item->id") ?>"> <?= $item->thumb_img() ?> <p> - <?= p::purify($item->title) ?> + <?= SafeString::purify($item->title) ?> </p> <div> - <?= nl2br(p::purify($item->description)) ?> + <?= nl2br(SafeString::purify($item->description)) ?> </div> </a> </li> @@ -44,7 +44,7 @@ <? else: ?> <p> - <?= t("No results found for <b>%term</b>", array("term" => p::clean($q))) ?> + <?= t("No results found for <b>%term</b>", array("term" => $q)) ?> </p> <? endif; ?> diff --git a/modules/server_add/controllers/admin_server_add.php b/modules/server_add/controllers/admin_server_add.php index 30109f42..fac2aa44 100644 --- a/modules/server_add/controllers/admin_server_add.php +++ b/modules/server_add/controllers/admin_server_add.php @@ -38,7 +38,7 @@ class Admin_Server_Add_Controller extends Admin_Controller { $path = $form->add_path->path->value; $paths[$path] = 1; module::set_var("server_add", "authorized_paths", serialize($paths)); - message::success(t("Added path %path", array("path" => p::clean($path)))); + message::success(t("Added path %path", array("path" => $path))); server_add::check_config($paths); url::redirect("admin/server_add"); } else { @@ -60,7 +60,7 @@ class Admin_Server_Add_Controller extends Admin_Controller { $paths = unserialize(module::get_var("server_add", "authorized_paths")); if (isset($paths[$path])) { unset($paths[$path]); - message::success(t("Removed path %path", array("path" => p::clean($path)))); + message::success(t("Removed path %path", array("path" => $path))); module::set_var("server_add", "authorized_paths", serialize($paths)); server_add::check_config($paths); } diff --git a/modules/server_add/views/server_add_tree.html.php b/modules/server_add/views/server_add_tree.html.php index 254a9da0..b68544ec 100644 --- a/modules/server_add/views/server_add_tree.html.php +++ b/modules/server_add/views/server_add_tree.html.php @@ -24,7 +24,7 @@ <? endif ?> file="<?= $file ?>" > - <?= p::clean(basename($file)) ?> + <?= SafeString::of(basename($file)) ?> </span> </li> <? endforeach ?> diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 431635f8..912e69b6 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -5,17 +5,17 @@ </script> <div id="gServerAdd"> - <h1 style="display: none;"><?= t("Add Photos to '%title'", array("title" => p::purify($item->title))) ?></h1> + <h1 style="display: none;"><?= t("Add Photos to '%title'", array("title" => SafeString::purify($item->title))) ?></h1> <p id="gDescription"><?= t("Photos will be added to album:") ?></p> <ul class="gBreadcrumbs"> <? foreach ($item->parents() as $parent): ?> <li> - <?= p::purify($parent->title) ?> + <?= SafeString::purify($parent->title) ?> </li> <? endforeach ?> <li class="active"> - <?= p::purify($item->title) ?> + <?= SafeString::purify($item->title) ?> </li> </ul> diff --git a/modules/tag/controllers/admin_tags.php b/modules/tag/controllers/admin_tags.php index dcdc16b9..f1b4ca3a 100644 --- a/modules/tag/controllers/admin_tags.php +++ b/modules/tag/controllers/admin_tags.php @@ -53,8 +53,8 @@ class Admin_Tags_Controller extends Admin_Controller { $name = $tag->name; Database::instance()->delete("items_tags", array("tag_id" => "$tag->id")); $tag->delete(); - message::success(t("Deleted tag %tag_name", array("tag_name" => p::clean($name)))); - log::success("tags", t("Deleted tag %tag_name", array("tag_name" => p::clean($name)))); + message::success(t("Deleted tag %tag_name", array("tag_name" => $name))); + log::success("tags", t("Deleted tag %tag_name", array("tag_name" => $name))); print json_encode( array("result" => "success", @@ -98,7 +98,7 @@ class Admin_Tags_Controller extends Admin_Controller { $tag->save(); $message = t("Renamed tag %old_name to %new_name", - array("old_name" => p::clean($old_name), "new_name" => p::clean($tag->name))); + array("old_name" => $old_name, "new_name" => $tag->name)); message::success($message); log::success("tags", $message); @@ -106,7 +106,7 @@ class Admin_Tags_Controller extends Admin_Controller { array("result" => "success", "location" => url::site("admin/tags"), "tag_id" => $tag->id, - "new_tagname" => p::clean($tag->name))); + "new_tagname" => SafeString::of($tag->name))); } else { print json_encode( array("result" => "error", diff --git a/modules/tag/helpers/tag_rss.php b/modules/tag/helpers/tag_rss.php index f94508cf..7194586d 100644 --- a/modules/tag/helpers/tag_rss.php +++ b/modules/tag/helpers/tag_rss.php @@ -22,7 +22,7 @@ class tag_rss_Core { static function available_feeds($item, $tag) { if ($tag) { $feeds["tag/tag/{$tag->id}"] = - t("Tag feed for %tag_name", array("tag_name" => p::clean($tag->name))); + t("Tag feed for %tag_name", array("tag_name" => $tag->name)); return $feeds; } return array(); diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php index 7d201da7..5bd23112 100644 --- a/modules/tag/views/admin_tags.html.php +++ b/modules/tag/views/admin_tags.html.php @@ -47,7 +47,7 @@ <? endif ?> <li> - <span id="gTag-<?= $tag->id ?>" class="gEditable tag-name"><?= p::clean($tag->name) ?></span> + <span id="gTag-<?= $tag->id ?>" class="gEditable tag-name"><?= SafeString::of($tag->name) ?></span> <span class="understate">(<?= $tag->count ?>)</span> <a href="<?= url::site("admin/tags/form_delete/$tag->id") ?>" class="gDialogLink delete-link gButtonLink"> diff --git a/modules/tag/views/tag_cloud.html.php b/modules/tag/views/tag_cloud.html.php index eba615fc..b4c6ae34 100644 --- a/modules/tag/views/tag_cloud.html.php +++ b/modules/tag/views/tag_cloud.html.php @@ -3,7 +3,7 @@ <? foreach ($tags as $tag): ?> <li class="size<?=(int)(($tag->count / $max_count) * 7) ?>"> <span><?= $tag->count ?> photos are tagged with </span> - <a href="<?= url::site("tags/$tag->id") ?>"><?= p::clean($tag->name) ?></a> + <a href="<?= url::site("tags/$tag->id") ?>"><?= SafeString::of($tag->name) ?></a> </li> <? endforeach ?> </ul> diff --git a/modules/user/controllers/admin_users.php b/modules/user/controllers/admin_users.php index f87602b8..521f82fa 100644 --- a/modules/user/controllers/admin_users.php +++ b/modules/user/controllers/admin_users.php @@ -51,7 +51,7 @@ class Admin_Users_Controller extends Controller { $user->save(); module::event("user_add_form_admin_completed", $user, $form); - message::success(t("Created user %user_name", array("user_name" => p::clean($user->name)))); + message::success(t("Created user %user_name", array("user_name" => $user->name))); print json_encode(array("result" => "success")); } else { print json_encode(array("result" => "error", @@ -84,7 +84,7 @@ class Admin_Users_Controller extends Controller { "form" => $form->__toString())); } - $message = t("Deleted user %user_name", array("user_name" => p::clean($name))); + $message = t("Deleted user %user_name", array("user_name" => $name)); log::success("user", $message); message::success($message); print json_encode(array("result" => "success")); @@ -142,7 +142,7 @@ class Admin_Users_Controller extends Controller { $user->save(); module::event("user_edit_form_admin_completed", $user, $form); - message::success(t("Changed user %user_name", array("user_name" => p::clean($user->name)))); + message::success(t("Changed user %user_name", array("user_name" => $user->name))); print json_encode(array("result" => "success")); } else { print json_encode(array("result" => "error", @@ -204,7 +204,7 @@ class Admin_Users_Controller extends Controller { $group = group::create($new_name); $group->save(); message::success( - t("Created group %group_name", array("group_name" => p::clean($group->name)))); + t("Created group %group_name", array("group_name" => $group->name))); print json_encode(array("result" => "success")); } else { print json_encode(array("result" => "error", @@ -233,7 +233,7 @@ class Admin_Users_Controller extends Controller { "form" => $form->__toString())); } - $message = t("Deleted group %group_name", array("group_name" => p::clean($name))); + $message = t("Deleted group %group_name", array("group_name" => $name)); log::success("group", $message); message::success($message); print json_encode(array("result" => "success")); @@ -271,11 +271,11 @@ class Admin_Users_Controller extends Controller { $group->name = $form->edit_group->inputs["name"]->value; $group->save(); message::success( - t("Changed group %group_name", array("group_name" => p::clean($group->name)))); + t("Changed group %group_name", array("group_name" => $group->name))); print json_encode(array("result" => "success")); } else { message::error( - t("Failed to change group %group_name", array("group_name" => p::clean($group->name)))); + t("Failed to change group %group_name", array("group_name" => $group->name))); print json_encode(array("result" => "error", "form" => $form->__toString())); } diff --git a/modules/user/controllers/login.php b/modules/user/controllers/login.php index 4d901051..b81b17b2 100644 --- a/modules/user/controllers/login.php +++ b/modules/user/controllers/login.php @@ -63,7 +63,7 @@ class Login_Controller extends Controller { log::warning( "user", t("Failed login for %name", - array("name" => p::clean($form->login->inputs["name"]->value)))); + array("name" => $form->login->inputs["name"]->value))); $form->login->inputs["name"]->add_error("invalid_login", 1); $valid = false; } @@ -71,7 +71,7 @@ class Login_Controller extends Controller { if ($valid) { user::login($user); - log::info("user", t("User %name logged in", array("name" => p::clean($user->name)))); + log::info("user", t("User %name logged in", array("name" => $user->name))); } // Either way, regenerate the session id to avoid session trapping diff --git a/modules/user/controllers/logout.php b/modules/user/controllers/logout.php index 099b1952..4b141a1c 100644 --- a/modules/user/controllers/logout.php +++ b/modules/user/controllers/logout.php @@ -23,8 +23,8 @@ class Logout_Controller extends Controller { $user = user::active(); user::logout(); - log::info("user", t("User %name logged out", array("name" => p::clean($user->name))), - html::anchor("user/$user->id", p::clean($user->name))); + log::info("user", t("User %name logged out", array("name" => $user->name)), + html::anchor("user/$user->id", SafeString::of($user->name))); if ($continue_url = $this->input->get("continue")) { $item = url::get_item_from_uri($continue_url); if (access::can("view", $item)) { diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index 7c432701..a6522369 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -72,7 +72,7 @@ class Password_Controller extends Controller { log::success( "user", - t("Password reset email sent for user %name", array("name" => p::clean($user->name)))); + t("Password reset email sent for user %name", array("name" => $user->name))); } else { // Don't include the username here until you're sure that it's XSS safe log::warning( diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index 9bd4c068..36c4f4fd 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -68,16 +68,16 @@ <td id="user-<?= $user->id ?>" class="core-info gDraggable"> <img src="<?= $user->avatar_url(20, $theme->url("images/avatar.jpg", true)) ?>" title="<?= t("Drag user onto group below to add as a new member") ?>" - alt="<?= p::clean($user->name) ?>" + alt="<?= SafeString::of($user->name) ?>" width="20" height="20" /> - <?= p::clean($user->name) ?> + <?= SafeString::of($user->name) ?> </td> <td> - <?= p::clean($user->full_name) ?> + <?= SafeString::of($user->full_name) ?> </td> <td> - <?= p::clean($user->email) ?> + <?= SafeString::of($user->email) ?> </td> <td> <?= ($user->last_login == 0) ? "" : gallery::date($user->last_login) ?> diff --git a/modules/user/views/admin_users_group.html.php b/modules/user/views/admin_users_group.html.php index bfd79dba..f89a4392 100644 --- a/modules/user/views/admin_users_group.html.php +++ b/modules/user/views/admin_users_group.html.php @@ -1,9 +1,9 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <h4> - <?= p::clean($group->name) ?> + <?= SafeString::of($group->name) ?> <? if (!$group->special): ?> <a href="<?= url::site("admin/users/delete_group_form/$group->id") ?>" - title="<?= t("Delete the %name group", array("name" => p::clean($group->name))) ?>" + title="<?= t("Delete the %name group", array("name" => $group->name)) ?>" class="gDialogLink gButtonLink ui-state-default ui-corner-all"> <span class="ui-icon ui-icon-trash"><?= t("delete") ?></span></a> <? else: ?> @@ -17,12 +17,12 @@ <ul> <? foreach ($group->users as $i => $user): ?> <li class="gUser"> - <?= p::clean($user->name) ?> + <?= SafeString::of($user->name) ?> <? if (!$group->special): ?> <a href="javascript:remove_user(<?= $user->id ?>, <?= $group->id ?>)" class="gButtonLink ui-state-default ui-corner-all ui-icon-left" title="<?= t("Remove %user from %group group", - array("user" => p::clean($user->name), "group" => p::clean($group->name))) ?>"> + array("user" => $user->name, "group" => $group->name)) ?>"> <span class="ui-icon ui-icon-closethick"><?= t("remove") ?></span> </a> <? endif ?> diff --git a/modules/user/views/login.html.php b/modules/user/views/login.html.php index 10ed31b2..e92513e7 100644 --- a/modules/user/views/login.html.php +++ b/modules/user/views/login.html.php @@ -8,11 +8,11 @@ </li> <? else: ?> <li class="first"> - <?= t('Logged in as %name', array('name' => - '<a href="' . url::site("form/edit/users/{$user->id}") . - '" title="' . t("Edit Your Profile") . + <?= t('Logged in as %name', array('name' => SafeString::of_safe_html( + '<a href="' . url::site("form/edit/users/{$user->id}") . + '" title="' . t("Edit Your Profile")->for_html_attr() . '" id="gUserProfileLink" class="gDialogLink">' . - p::clean($user->display_name()) . '</a>')) ?> + SafeString::of($user->display_name()) . '</a>'))) ?> </li> <li> <a href="<?= url::site("logout?csrf=$csrf&continue=" . urlencode(url::current(true))) ?>" diff --git a/modules/user/views/reset_password.html.php b/modules/user/views/reset_password.html.php index 4c4672ee..3dc7aebf 100644 --- a/modules/user/views/reset_password.html.php +++ b/modules/user/views/reset_password.html.php @@ -6,7 +6,7 @@ <body> <h2><?= t("Password Reset Request") ?> </h2> <p> - <?= t("Hello, %name,", array("name" => p::clean($user->full_name ? $user->full_name : $user->name))) ?> + <?= t("Hello, %name,", array("name" => $user->full_name ? $user->full_name : $user->name)) ?> </p> <p> <?= t("We received a request to reset your password for <a href=\"%site_url\">%site_url</a>. If you made this request, you can confirm it by <a href=\"%confirm_url\">clicking this link</a>. If you didn't request this password reset, it's ok to ignore this mail.", array("site_url" => url::base(false, "http"), "confirm_url" => $confirm_url)) ?> diff --git a/system/helpers/request.php b/system/helpers/request.php index 4203d0e5..15b8edfa 100644 --- a/system/helpers/request.php +++ b/system/helpers/request.php @@ -30,7 +30,7 @@ class request_Core { // Set referrer $ref = $_SERVER['HTTP_REFERER']; - if (strpos($ref, url::base(FALSE)) === 0) + if (strpos($ref, (string) url::base(FALSE)) === 0) { // Remove the base URL from the referrer $ref = substr($ref, strlen(url::base(FALSE))); diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index 3f4128cb..2ed8c38e 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -23,7 +23,7 @@ <?= $theme->script("gallery.common.js") ?> <? /* MSG_CANCEL is required by gallery.dialog.js */ ?> <script type="text/javascript"> - var MSG_CANCEL = "<?= t('Cancel') ?>"; + var MSG_CANCEL = "<?= t('Cancel')->for_js() ?>"; </script> <?= $theme->script("gallery.ajax.js") ?> <?= $theme->script("gallery.dialog.js") ?> diff --git a/themes/default/views/album.html.php b/themes/default/views/album.html.php index e2890482..8c690f5f 100644 --- a/themes/default/views/album.html.php +++ b/themes/default/views/album.html.php @@ -2,8 +2,8 @@ <? // @todo Set hover on AlbumGrid list items for guest users ?> <div id="gInfo"> <?= $theme->album_top() ?> - <h1><?= p::purify($item->title) ?></h1> - <div class="gDescription"><?= nl2br(p::purify($item->description)) ?></div> + <h1><?= SafeString::purify($item->title) ?></h1> + <div class="gDescription"><?= nl2br(SafeString::purify($item->description)) ?></div> </div> <ul id="gAlbumGrid"> @@ -20,7 +20,7 @@ </a> <?= $theme->thumb_bottom($child) ?> <?= $theme->context_menu($child, "#gItemId-{$child->id} .gThumbnail") ?> - <h2><span></span><a href="<?= $child->url() ?>"><?= p::clean($child->title) ?></a></h2> + <h2><span></span><a href="<?= $child->url() ?>"><?= SafeString::of($child->title) ?></a></h2> <ul class="gMetadata"> <?= $theme->thumb_info($child) ?> </ul> diff --git a/themes/default/views/dynamic.html.php b/themes/default/views/dynamic.html.php index 2d122e69..2d8e04a2 100644 --- a/themes/default/views/dynamic.html.php +++ b/themes/default/views/dynamic.html.php @@ -3,7 +3,7 @@ <div id="gAlbumHeaderButtons"> <?= $theme->dynamic_top() ?> </div> - <h1><?= p::clean($title) ?></h1> + <h1><?= SafeString::of($title) ?></h1> </div> <ul id="gAlbumGrid"> @@ -16,7 +16,7 @@ width="<?= $child->thumb_width ?>" height="<?= $child->thumb_height ?>" /> </a> - <h2><?= p::purify($child->title) ?></h2> + <h2><?= SafeString::purify($child->title) ?></h2> <?= $theme->thumb_bottom($child) ?> <ul class="gMetadata"> <?= $theme->thumb_info($child) ?> diff --git a/themes/default/views/header.html.php b/themes/default/views/header.html.php index 2ba1e923..9e34401d 100644 --- a/themes/default/views/header.html.php +++ b/themes/default/views/header.html.php @@ -19,10 +19,10 @@ <? foreach ($parents as $parent): ?> <li> <a href="<?= url::site("albums/{$parent->id}?show=$item->id") ?>"> - <?= p::purify($parent->title) ?> + <?= SafeString::purify($parent->title) ?> </a> </li> <? endforeach ?> - <li class="active"><?= p::purify($item->title) ?></li> + <li class="active"><?= SafeString::purify($item->title) ?></li> </ul> <? endif ?> diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 29789f8e..237743b7 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -28,8 +28,8 @@ <?= $item->movie_img(array("class" => "gMovie", "id" => "gMovieId-{$item->id}")) ?> <div id="gInfo"> - <h1><?= p::purify($item->title) ?></h1> - <div><?= nl2br(p::purify($item->description)) ?></div> + <h1><?= SafeString::purify($item->title) ?></h1> + <div><?= nl2br(SafeString::purify($item->description)) ?></div> </div> <?= $theme->photo_bottom() ?> diff --git a/themes/default/views/page.html.php b/themes/default/views/page.html.php index 2cb71b9e..844ef295 100644 --- a/themes/default/views/page.html.php +++ b/themes/default/views/page.html.php @@ -10,14 +10,14 @@ <? else: ?> <? if ($theme->item()): ?> <? if ($theme->item()->is_album()): ?> - <?= t("Browse Album :: %album_title", array("album_title" => p::clean($theme->item()->title))) ?> + <?= t("Browse Album :: %album_title", array("album_title" => $theme->item()->title)) ?> <? elseif ($theme->item()->is_photo()): ?> - <?= t("Photo :: %photo_title", array("photo_title" => p::clean($theme->item()->title))) ?> + <?= t("Photo :: %photo_title", array("photo_title" => $theme->item()->title)) ?> <? else: ?> - <?= t("Movie :: %movie_title", array("movie_title" => p::clean($theme->item()->title))) ?> + <?= t("Movie :: %movie_title", array("movie_title" => $theme->item()->title)) ?> <? endif ?> <? elseif ($theme->tag()): ?> - <?= t("Browse Tag :: %tag_title", array("tag_title" => p::clean($theme->tag()->name))) ?> + <?= t("Browse Tag :: %tag_title", array("tag_title" => $theme->tag()->name)) ?> <? else: /* Not an item, not a tag, no page_title specified. Help! */ ?> <?= t("Gallery") ?> <? endif ?> @@ -51,7 +51,7 @@ <?= $theme->script("gallery.common.js") ?> <? /* MSG_CANCEL is required by gallery.dialog.js */ ?> <script type="text/javascript"> - var MSG_CANCEL = "<?= t('Cancel') ?>"; + var MSG_CANCEL = "<?= t('Cancel')->for_js() ?>"; </script> <?= $theme->script("gallery.ajax.js") ?> <?= $theme->script("gallery.dialog.js") ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 39e61ef6..5b5cb12b 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ <script> $(document).ready(function() { $(".gFullSizeLink").click(function() { - $.gallery_show_full_size("<?= $theme->item()->file_url() ?>", "<?= $theme->item()->width ?>", "<?= $theme->item()->height ?>"); + $.gallery_show_full_size("<?= $theme->item()->file_url()->for_js() ?>", "<?= $theme->item()->width ?>", "<?= $theme->item()->height ?>"); return false; }); }); @@ -51,8 +51,8 @@ </div> <div id="gInfo"> - <h1><?= p::purify($item->title) ?></h1> - <div><?= nl2br(p::purify($item->description)) ?></div> + <h1><?= SafeString::purify($item->title) ?></h1> + <div><?= nl2br(SafeString::purify($item->description)) ?></div> </div> <?= $theme->photo_bottom() ?> |