summaryrefslogtreecommitdiff
path: root/modules/gallery/tests
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gallery/tests')
-rw-r--r--modules/gallery/tests/Controller_Auth_Test.php252
-rw-r--r--modules/gallery/tests/Item_Model_Test.php10
-rw-r--r--modules/gallery/tests/Locales_Helper_Test.php10
-rw-r--r--modules/gallery/tests/Xss_Security_Test.php3
-rw-r--r--modules/gallery/tests/controller_auth_data.txt40
-rw-r--r--modules/gallery/tests/xss_data.txt44
6 files changed, 338 insertions, 21 deletions
diff --git a/modules/gallery/tests/Controller_Auth_Test.php b/modules/gallery/tests/Controller_Auth_Test.php
new file mode 100644
index 00000000..caf6d8f2
--- /dev/null
+++ b/modules/gallery/tests/Controller_Auth_Test.php
@@ -0,0 +1,252 @@
+<?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 Controller_Auth_Test extends Unit_Test_Case {
+ static $rest_methods = array("_index", "_show", "_form_edit", "_form_add", "_create",
+ "_update", "_delete");
+
+ static $rest_methods_with_csrf_check = array("_update", "_delete", "_create");
+
+ public function find_missing_auth_test() {
+ $found = array();
+ $controllers = glob("*/*/controllers/*.php");
+ $feeds = glob("*/*/helpers/*_rss.php");
+ foreach (array_merge($controllers, $feeds) as $controller) {
+ if (preg_match("{modules/(gallery_)?unit_test/}", $controller)) {
+ continue;
+ }
+
+ // List of all tokens without whitespace, simplifying parsing.
+ $tokens = array();
+ foreach (token_get_all(file_get_contents($controller)) as $token) {
+ if (!is_array($token) || $token[0] != T_WHITESPACE) {
+ $tokens[] = $token;
+ }
+ }
+
+ $is_admin_controller = false;
+ $is_rest_controller = false;
+
+ $open_braces = 0;
+ $function = null;
+ for ($token_number = 0; $token_number < count($tokens); $token_number++) {
+ $token = $tokens[$token_number];
+
+ // Count braces.
+ // 1 open brace = in class context.
+ // 2 open braces = in function.
+ if (!is_array($token)) {
+ if ($token == "}") {
+ $open_braces--;
+ if ($open_braces == 1 && $function) {
+ $found[$controller][] = $function;
+ $function = null;
+ } else if ($open_braces == 0) {
+ $is_admin_controller = false;
+ $is_rest_controller = false;
+ }
+ } else if ($token == "{") {
+ $open_braces++;
+ }
+ } else {
+ // An array token
+
+ if ($open_braces == 0 && $token[0] == T_EXTENDS) {
+ if (self::_token_matches(array(T_STRING, "Admin_Controller"), $tokens, $token_number + 1)) {
+ $is_admin_controller = true;
+ } else if (self::_token_matches(array(T_STRING, "REST_Controller"), $tokens, $token_number + 1)) {
+ $is_rest_controller = true;
+ }
+ } else if ($open_braces == 1 && $token[0] == T_FUNCTION) {
+ $line = $token[2];
+ $name = "";
+ // Search backwards to check visibility,
+ // "private function", or "private static function"
+ $previous = $tokens[$token_number - 1][0];
+ $previous_2 = $tokens[$token_number - 2][0];
+ $is_private = in_array($previous, array(T_PRIVATE, T_PROTECTED)) ||
+ in_array($previous_2, array(T_PRIVATE, T_PROTECTED));
+ $is_static = $previous == T_STATIC || $previous_2 == T_STATIC;
+
+ // Search forward to get function name
+ do {
+ $token_number++;
+ if (self::_token_matches(array(T_STRING), $tokens, $token_number)) {
+ $token = $tokens[$token_number];
+ $name = $token[1];
+ break;
+ }
+ } while ($token_number < count($tokens));
+
+ $is_rss_feed = $name == "feed" && strpos(basename($controller), "_rss.php");
+
+ if ((!$is_static || $is_rss_feed) &&
+ (!$is_private ||
+ ($is_rest_controller && in_array($name, self::$rest_methods)))) {
+ $function = self::_function($name, $line, $is_admin_controller);
+ if ($is_rest_controller && in_array($name, self::$rest_methods_with_csrf_check)) {
+ $function->checks_csrf(true);
+ }
+ }
+ }
+
+ // Check body of all public functions
+ //
+ // Authorization
+ // Require: access::required\(
+ // Authentication (CSRF token)
+ // [When using Input, $this->input, Forge]
+ // Require: ->validate() or access::verify_csrf\(
+ if ($function && $open_braces >= 2) {
+ if ($token[0] == T_STRING) {
+ if ($token[1] == "access" &&
+ 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("forbidden", "required")) &&
+ self::_token_matches("(", $tokens, $token_number + 3)) {
+ $token_number += 3;
+ $function->checks_authorization(true);
+ } else if ($token[1] == "access" &&
+ self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) &&
+ self::_token_matches(array(T_STRING, "verify_csrf"), $tokens, $token_number + 2) &&
+ self::_token_matches("(", $tokens, $token_number + 3)) {
+ $token_number += 3;
+ $function->checks_csrf(true);
+ } else if (in_array($token[1], array("Input", "Forge")) &&
+ self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1)) {
+ $token_number++;
+ $function->uses_input(true);
+ }
+ } else if ($token[0] == T_VARIABLE) {
+ if ($token[1] == '$this' &&
+ self::_token_matches(array(T_OBJECT_OPERATOR), $tokens, $token_number + 1) &&
+ self::_token_matches(array(T_STRING, "input"), $tokens, $token_number + 2)) {
+ $token_number += 2;
+ $function->uses_input(true);
+ }
+ } else if ($token[0] == T_OBJECT_OPERATOR) {
+ if (self::_token_matches(array(T_STRING, "validate"), $tokens, $token_number + 1) &&
+ self::_token_matches("(", $tokens, $token_number + 2)) {
+ $token_number += 2;
+ $function->checks_csrf(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Generate the report
+ $new = TMPPATH . "controller_auth_data.txt";
+ $fd = fopen($new, "wb");
+ ksort($found);
+ foreach ($found as $controller => $functions) {
+ $is_admin_controller = true;
+ foreach ($functions as $function) {
+ $is_admin_controller &= $function->is_admin_controller;
+ $flags = array();
+ if ($function->uses_input() && !$function->checks_csrf()) {
+ $flags[] = "DIRTY_CSRF";
+ }
+ if (!$function->is_admin_controller && !$function->checks_authorization()) {
+ $flags[] = "DIRTY_AUTH";
+ }
+
+ if (!$flags) {
+ // Don't print CLEAN instances
+ continue;
+ }
+
+ fprintf($fd, "%-60s %-20s %s\n",
+ $controller, $function->name, implode("|", $flags));
+ }
+
+ if (strpos(basename($controller), "admin_") === 0 && !$is_admin_controller) {
+ fprintf($fd, "%-60s %-20s %s\n",
+ $controller, basename($controller), "NO_ADMIN_CONTROLLER");
+ }
+ }
+ fclose($fd);
+
+ // Compare with the expected report from our golden file.
+ $canonical = MODPATH . "gallery/tests/controller_auth_data.txt";
+ exec("diff $canonical $new", $output, $return_value);
+ $this->assert_false(
+ $return_value, "Controller auth golden file mismatch. Output:\n" . implode("\n", $output) );
+ }
+
+ 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;
+ }
+ }
+
+ static function _function($name, $line, $is_admin_controller) {
+ return new Controller_Auth_Test_Function($name, $line, $is_admin_controller);
+ }
+}
+
+class Controller_Auth_Test_Function {
+ public $name;
+ public $line;
+ public $is_admin_controller = false;
+ private $_uses_input = false;
+ private $_checks_authorization = false;
+ private $_checks_csrf = false;
+
+ function __construct($name, $line, $is_admin_controller) {
+ $this->name = $name;
+ $this->line = $line;
+ $this->is_admin_controller = $is_admin_controller;
+ }
+
+ function uses_input($val=null) {
+ if ($val !== null) {
+ $this->_uses_input = (bool) $val;
+ }
+ return $this->_uses_input;
+ }
+
+ function checks_authorization($val=null) {
+ if ($val !== null) {
+ $this->_checks_authorization = (bool) $val;
+ }
+ return $this->_checks_authorization;
+ }
+
+ function checks_csrf($val=null) {
+ if ($val !== null) {
+ $this->_checks_csrf = $val;
+ }
+ return $this->_checks_csrf;
+ }
+} \ No newline at end of file
diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php
index 585e247c..84210e4c 100644
--- a/modules/gallery/tests/Item_Model_Test.php
+++ b/modules/gallery/tests/Item_Model_Test.php
@@ -150,4 +150,14 @@ class Item_Model_Test extends Unit_Test_Case {
$this->assert_same("ORIGINAL_VALUE", $item->original()->title);
$this->assert_same("NEW_VALUE", $item->title);
}
+
+ public function urls_are_rawurlencoded_test() {
+ $item = self::_create_random_item();
+ $item->slug = "foo bar";
+ $item->name = "foo bar.jpg";
+ $item->save();
+
+ $this->assert_equal("foo%20bar", $item->relative_url());
+ $this->assert_equal("foo%20bar.jpg", $item->relative_path());
+ }
}
diff --git a/modules/gallery/tests/Locales_Helper_Test.php b/modules/gallery/tests/Locales_Helper_Test.php
index 85b8e206..4c03d8d4 100644
--- a/modules/gallery/tests/Locales_Helper_Test.php
+++ b/modules/gallery/tests/Locales_Helper_Test.php
@@ -67,7 +67,7 @@ class Locales_Helper_Test extends Unit_Test_Case {
locales::update_installed(array("no_NO", "pt_PT", "ja_JP"));
$_SERVER["HTTP_ACCEPT_LANGUAGE"] = "en,en-us,ja_JP;q=0.7,no-fr;q=0.9";
$locale = locales::locale_from_http_request();
- $this->assert_equal("ja_JP", $locale);
+ $this->assert_equal("no_NO", $locale);
}
public function locale_from_http_request_best_match_vs_installed_2_test() {
@@ -83,4 +83,12 @@ class Locales_Helper_Test extends Unit_Test_Case {
$locale = locales::locale_from_http_request();
$this->assert_equal(null, $locale);
}
+
+ public function locale_from_http_request_prefer_inexact_same_language_match_over_exact_other_language_match_test() {
+ locales::update_installed(array("de_DE", "ar_AR", "fa_IR", "he_IL", "en_US"));
+ // Accept-Language header from Firefox 3.5/Ubuntu
+ $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "he,en-us;q=0.9,de-ch;q=0.5,en;q=0.3";
+ $locale = locales::locale_from_http_request();
+ $this->assert_equal("he_IL", $locale);
+ }
} \ No newline at end of file
diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php
index 85624517..16541017 100644
--- a/modules/gallery/tests/Xss_Security_Test.php
+++ b/modules/gallery/tests/Xss_Security_Test.php
@@ -144,7 +144,8 @@ class Xss_Security_Test extends Unit_Test_Case {
"dynamic_bottom", "dynamic_top", "footer", "head", "header_bottom",
"header_top", "page_bottom", "page_top", "photo_blocks", "photo_bottom",
"photo_top", "resize_bottom", "resize_top", "sidebar_blocks", "sidebar_bottom",
- "sidebar_top", "thumb_bottom", "thumb_info", "thumb_top")) &&
+ "sidebar_top", "thumb_bottom", "thumb_info", "thumb_top",
+ "movie_menu")) &&
self::_token_matches("(", $tokens, $token_number + 3)) {
$method = $tokens[$token_number + 2][1];
diff --git a/modules/gallery/tests/controller_auth_data.txt b/modules/gallery/tests/controller_auth_data.txt
new file mode 100644
index 00000000..fdf00c5e
--- /dev/null
+++ b/modules/gallery/tests/controller_auth_data.txt
@@ -0,0 +1,40 @@
+modules/comment/controllers/admin_comments.php queue DIRTY_CSRF
+modules/comment/controllers/comments.php _index DIRTY_CSRF
+modules/comment/helpers/comment_rss.php feed DIRTY_AUTH
+modules/digibug/controllers/digibug.php print_proxy DIRTY_CSRF|DIRTY_AUTH
+modules/digibug/controllers/digibug.php close_window DIRTY_AUTH
+modules/gallery/controllers/admin.php __call DIRTY_AUTH
+modules/gallery/controllers/albums.php _show DIRTY_CSRF
+modules/gallery/controllers/albums.php _form_add DIRTY_CSRF
+modules/gallery/controllers/combined.php javascript DIRTY_AUTH
+modules/gallery/controllers/combined.php css DIRTY_AUTH
+modules/gallery/controllers/file_proxy.php __call DIRTY_CSRF|DIRTY_AUTH
+modules/gallery/controllers/maintenance.php index DIRTY_AUTH
+modules/gallery/controllers/rest.php __construct DIRTY_AUTH
+modules/gallery/controllers/rest.php __call DIRTY_AUTH
+modules/gallery/controllers/rest.php form_edit DIRTY_AUTH
+modules/gallery/controllers/rest.php form_add DIRTY_AUTH
+modules/gallery/controllers/rest.php _index DIRTY_AUTH
+modules/gallery/controllers/rest.php _create DIRTY_AUTH
+modules/gallery/controllers/rest.php _show DIRTY_AUTH
+modules/gallery/controllers/rest.php _update DIRTY_AUTH
+modules/gallery/controllers/rest.php _delete DIRTY_AUTH
+modules/gallery/controllers/rest.php _form_add DIRTY_AUTH
+modules/gallery/controllers/rest.php _form_edit DIRTY_AUTH
+modules/gallery/controllers/simple_uploader.php start DIRTY_AUTH
+modules/gallery/controllers/simple_uploader.php finish DIRTY_AUTH
+modules/gallery/controllers/upgrader.php index DIRTY_AUTH
+modules/gallery/controllers/welcome_message.php index DIRTY_AUTH
+modules/rss/controllers/rss.php feed DIRTY_CSRF|DIRTY_AUTH
+modules/search/controllers/search.php index DIRTY_CSRF|DIRTY_AUTH
+modules/server_add/controllers/admin_server_add.php autocomplete DIRTY_CSRF
+modules/server_add/controllers/server_add.php children DIRTY_CSRF
+modules/tag/controllers/admin_tags.php index DIRTY_CSRF
+modules/tag/controllers/tags.php _show DIRTY_CSRF|DIRTY_AUTH
+modules/user/controllers/login.php ajax DIRTY_AUTH
+modules/user/controllers/login.php auth_ajax DIRTY_AUTH
+modules/user/controllers/login.php html DIRTY_AUTH
+modules/user/controllers/login.php auth_html DIRTY_AUTH
+modules/user/controllers/logout.php index DIRTY_CSRF|DIRTY_AUTH
+modules/user/controllers/password.php reset DIRTY_AUTH
+modules/user/controllers/password.php do_reset DIRTY_CSRF|DIRTY_AUTH
diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt
index 8c71740e..57da8730 100644
--- a/modules/gallery/tests/xss_data.txt
+++ b/modules/gallery/tests/xss_data.txt
@@ -48,6 +48,7 @@ modules/gallery/views/admin_block_log_entries.html.php 8 DIRTY $entry
modules/gallery/views/admin_block_news.html.php 5 DIRTY_JS $entry["link"]
modules/gallery/views/admin_block_news.html.php 5 DIRTY $entry["title"]
modules/gallery/views/admin_block_news.html.php 7 DIRTY text::limit_words(strip_tags($entry["description"]),25);
+modules/gallery/views/admin_block_photo_stream.html.php 5 DIRTY_JS $photo->url()
modules/gallery/views/admin_block_photo_stream.html.php 6 DIRTY photo::img_dimensions($photo->width,$photo->height,72)
modules/gallery/views/admin_block_photo_stream.html.php 7 DIRTY_ATTR $photo->thumb_url()
modules/gallery/views/admin_dashboard.html.php 5 DIRTY_JS $csrf
@@ -180,14 +181,14 @@ modules/image_block/views/image_block_block.html.php 3 DIRTY_JS $item-
modules/image_block/views/image_block_block.html.php 4 DIRTY $item->thumb_img(array("class"=>"gThumbnail"))
modules/info/views/info_block.html.php 22 DIRTY date("M j, Y H:i:s",$item->captured)
modules/info/views/info_block.html.php 29 DIRTY_JS $item->owner->url
-modules/notification/views/comment_published.html.php 28 DIRTY_JS $comment->item()->url(array(),true)
-modules/notification/views/comment_published.html.php 29 DIRTY $comment->item()->url(array(),true)
-modules/notification/views/item_added.html.php 16 DIRTY_JS $item->url(array(),true)
-modules/notification/views/item_added.html.php 17 DIRTY $item->url(array(),true)
-modules/notification/views/item_deleted.html.php 18 DIRTY_JS $item->parent()->url(array(),true)
-modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->url(array(),true)
-modules/notification/views/item_updated.html.php 20 DIRTY_JS $item->url(array(),true)
-modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(),true)
+modules/notification/views/comment_published.html.php 28 DIRTY_JS $comment->item()->abs_url()
+modules/notification/views/comment_published.html.php 29 DIRTY $comment->item()->abs_url()
+modules/notification/views/item_added.html.php 16 DIRTY_JS $item->abs_url()
+modules/notification/views/item_added.html.php 17 DIRTY $item->abs_url()
+modules/notification/views/item_deleted.html.php 18 DIRTY_JS $item->parent()->abs_url()
+modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->abs_url()
+modules/notification/views/item_updated.html.php 20 DIRTY_JS $item->abs_url()
+modules/notification/views/item_updated.html.php 20 DIRTY $item->abs_url()
modules/organize/views/organize_dialog.html.php 3 DIRTY_JS url::site("organize/move_to/__ALBUM_ID__?csrf=$csrf")
modules/organize/views/organize_dialog.html.php 4 DIRTY_JS url::site("organize/rearrange/__TARGET_ID__/__BEFORE__?csrf=$csrf")
modules/organize/views/organize_dialog.html.php 5 DIRTY_JS url::site("organize/sort_order/__ALBUM_ID__/__COL__/__DIR__?csrf=$csrf")
@@ -246,6 +247,7 @@ modules/rss/views/feed.mrss.php 73 DIRTY_ATTR $chi
modules/rss/views/feed.mrss.php 74 DIRTY_ATTR $child->mime_type
modules/rss/views/rss_block.html.php 6 DIRTY_JS rss::url($url)
modules/search/views/search.html.php 30 DIRTY_ATTR $item_class
+modules/search/views/search.html.php 31 DIRTY_JS $item->url()
modules/search/views/search.html.php 32 DIRTY $item->thumb_img()
modules/server_add/views/admin_server_add.html.php 15 DIRTY_ATTR $id
modules/server_add/views/admin_server_add.html.php 24 DIRTY $form
@@ -285,6 +287,7 @@ themes/admin_default/views/admin.html.php 15 DIRTY_JS $theme
themes/admin_default/views/admin.html.php 32 DIRTY $theme->admin_head()
themes/admin_default/views/admin.html.php 36 DIRTY $theme->admin_page_top()
themes/admin_default/views/admin.html.php 44 DIRTY $theme->admin_header_top()
+themes/admin_default/views/admin.html.php 49 DIRTY_JS item::root()->url()
themes/admin_default/views/admin.html.php 53 DIRTY $theme->admin_menu()
themes/admin_default/views/admin.html.php 55 DIRTY $theme->admin_header_bottom()
themes/admin_default/views/admin.html.php 62 DIRTY $content
@@ -292,10 +295,11 @@ themes/admin_default/views/admin.html.php 68 DIRTY $sideb
themes/admin_default/views/admin.html.php 73 DIRTY $theme->admin_footer()
themes/admin_default/views/admin.html.php 75 DIRTY $theme->admin_credits()
themes/admin_default/views/admin.html.php 79 DIRTY $theme->admin_page_bottom()
-themes/admin_default/views/block.html.php 2 DIRTY $id
-themes/admin_default/views/block.html.php 2 DIRTY_ATTR $css_id
-themes/admin_default/views/block.html.php 10 DIRTY $title
-themes/admin_default/views/block.html.php 13 DIRTY $content
+themes/admin_default/views/block.html.php 3 DIRTY_ATTR $anchor
+themes/admin_default/views/block.html.php 5 DIRTY $id
+themes/admin_default/views/block.html.php 5 DIRTY_ATTR $css_id
+themes/admin_default/views/block.html.php 13 DIRTY $title
+themes/admin_default/views/block.html.php 16 DIRTY $content
themes/admin_default/views/pager.html.php 13 DIRTY_JS str_replace('{page}',1,$url)
themes/admin_default/views/pager.html.php 20 DIRTY_JS str_replace('{page}',$previous_page,$url)
themes/admin_default/views/pager.html.php 27 DIRTY $from_to_msg
@@ -306,10 +310,10 @@ themes/default/views/album.html.php 16 DIRTY_ATTR $ite
themes/default/views/album.html.php 18 DIRTY_JS $child->url()
themes/default/views/album.html.php 19 DIRTY $child->thumb_img(array("class"=>"gThumbnail"))
themes/default/views/album.html.php 23 DIRTY_JS $child->url()
-themes/default/views/block.html.php 2 DIRTY_ATTR $anchor
-themes/default/views/block.html.php 3 DIRTY_ATTR $css_id
-themes/default/views/block.html.php 4 DIRTY $title
-themes/default/views/block.html.php 6 DIRTY $content
+themes/default/views/block.html.php 3 DIRTY_ATTR $anchor
+themes/default/views/block.html.php 5 DIRTY_ATTR $css_id
+themes/default/views/block.html.php 6 DIRTY $title
+themes/default/views/block.html.php 8 DIRTY $content
themes/default/views/dynamic.html.php 11 DIRTY_ATTR $child->is_album()?"gAlbum":""
themes/default/views/dynamic.html.php 13 DIRTY_JS $child->url()
themes/default/views/dynamic.html.php 14 DIRTY_ATTR $child->id
@@ -325,9 +329,11 @@ themes/default/views/page.html.php 41 DIRTY $new_w
themes/default/views/page.html.php 42 DIRTY $new_height
themes/default/views/page.html.php 43 DIRTY $thumb_proportion
themes/default/views/page.html.php 82 DIRTY $header_text
-themes/default/views/page.html.php 112 DIRTY $content
-themes/default/views/page.html.php 118 DIRTY newView("sidebar.html")
-themes/default/views/page.html.php 125 DIRTY $footer_text
+themes/default/views/page.html.php 84 DIRTY_JS item::root()->url()
+themes/default/views/page.html.php 102 DIRTY_JS $parent->url($parent==$theme->item()->parent()?"show={$theme->item()->id}":null)
+themes/default/views/page.html.php 117 DIRTY $content
+themes/default/views/page.html.php 123 DIRTY newView("sidebar.html")
+themes/default/views/page.html.php 130 DIRTY $footer_text
themes/default/views/pager.html.php 13 DIRTY_JS str_replace('{page}',1,$url)
themes/default/views/pager.html.php 20 DIRTY_JS str_replace('{page}',$previous_page,$url)
themes/default/views/pager.html.php 27 DIRTY $from_to_msg