From 04f34516f89451b5a3af6a122f740dc30112e597 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:05:15 +0200 Subject: Improve compatibility with other RDBMS --- modules/search/helpers/search.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/search/helpers/search.php b/modules/search/helpers/search.php index 15efa3b2..9046ad2d 100644 --- a/modules/search/helpers/search.php +++ b/modules/search/helpers/search.php @@ -45,7 +45,7 @@ class search_Core { "WHERE MATCH({search_records}.`data`) AGAINST ('$q' IN BOOLEAN MODE) " . $access_sql . "ORDER BY `score` DESC " . - "LIMIT $offset, $limit"; + "LIMIT $limit OFFSET $offset"; return array($count, new ORM_Iterator(ORM::factory("item"), $db->query($query))); } -- cgit v1.2.3 From 2e6a1d6fdc562b2ff797deaf8b8ab019c17ed113 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:08:55 +0200 Subject: SQL is case insensitive --- modules/search/helpers/search.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/search/helpers/search.php b/modules/search/helpers/search.php index 9046ad2d..ea8dad81 100644 --- a/modules/search/helpers/search.php +++ b/modules/search/helpers/search.php @@ -34,11 +34,11 @@ class search_Core { // Count the total number of rows. We can't do this with our regular query because of the // limit statement. It's possible that if we get rid of the limit (but keep the offset) on // the 2nd query and combine the two, it might be faster than making 2 separate queries. - $count_query = "SELECT COUNT(*) AS C " . + $count_query = "SELECT COUNT(*) AS c " . "FROM {items} JOIN {search_records} ON ({items}.`id` = {search_records}.`item_id`) " . "WHERE MATCH({search_records}.`data`) AGAINST ('$q' IN BOOLEAN MODE) " . $access_sql; - $count = $db->query($count_query)->current()->C; + $count = $db->query($count_query)->current()->c; $query = "SELECT {items}.*, MATCH({search_records}.`data`) AGAINST ('$q') AS `score` " . "FROM {items} JOIN {search_records} ON ({items}.`id` = {search_records}.`item_id`) " . -- cgit v1.2.3 From c80d2da0a95a63b76f5a4c835f1a0e1022ec2f53 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:09:46 +0200 Subject: Remove an useless ORDER BY. It improves compatibility with PgSQL. --- modules/gallery/models/item.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 7dce9e51..44d79d5b 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -382,8 +382,7 @@ class Item_Model extends ORM_MPTT { SELECT COUNT(*) AS position FROM {items} WHERE parent_id = {$this->id} AND {$this->sort_column} <= (SELECT {$this->sort_column} - FROM {items} WHERE id = $child_id) - ORDER BY {$this->sort_column} {$this->sort_order}"); + FROM {items} WHERE id = $child_id)"); return $result->current()->position; } -- cgit v1.2.3 From d601ab93beb9be2cc69d64fa04803ff3c3601c3a Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:12:09 +0200 Subject: Value stored in comment.state is not 15 char length. Use a VARCHAR instead of a CHAR. It improves compatibility with PgSQL. --- installer/install.sql | 2 +- modules/comment/helpers/comment_installer.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/installer/install.sql b/installer/install.sql index 432aee64..b9c56043 100755 --- a/installer/install.sql +++ b/installer/install.sql @@ -55,7 +55,7 @@ CREATE TABLE {comments} ( `server_remote_addr` varchar(32) default NULL, `server_remote_host` varchar(64) default NULL, `server_remote_port` varchar(16) default NULL, - `state` char(15) default 'unpublished', + `state` varchar(15) default 'unpublished', `text` text, `updated` int(9) NOT NULL, PRIMARY KEY (`id`) diff --git a/modules/comment/helpers/comment_installer.php b/modules/comment/helpers/comment_installer.php index b1cfcdc0..58bce8e0 100644 --- a/modules/comment/helpers/comment_installer.php +++ b/modules/comment/helpers/comment_installer.php @@ -43,7 +43,7 @@ class comment_installer { `server_remote_addr` varchar(32) default NULL, `server_remote_host` varchar(64) default NULL, `server_remote_port` varchar(16) default NULL, - `state` char(15) default 'unpublished', + `state` varchar(15) default 'unpublished', `text` text, `updated` int(9) NOT NULL, PRIMARY KEY (`id`)) -- cgit v1.2.3 From de28b0350e5d5bf6c3e1eb5a9531298b08fd7cba Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:14:38 +0200 Subject: Use an integer because the code store 0 and 1. It improves compatiblity with PgSQL. The right way is to use a BOOLEAN and code with booleans. The values would be : - FALSE => deny - TRUE => allow - NULL => unknow --- modules/gallery/helpers/access.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index c48f0b79..7b01058c 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -426,7 +426,7 @@ class access_Core { $field = "{$perm_name}_{$group->id}"; $cache_table = $perm_name == "view" ? "items" : "access_caches"; $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0"); - $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL"); + $db->query("ALTER TABLE {access_intents} ADD `$field` SMALLINT DEFAULT NULL"); $db->update("access_intents", array($field => 0), array("item_id" => 1)); ORM::factory("access_intent")->clear_cache(); } -- cgit v1.2.3 From be354ab98bbb08abad0a7efd6fb1d110e11381de Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Wed, 24 Jun 2009 23:40:47 +0200 Subject: Remove an useless ORDER BY. It improves compatibility with PgSQL. (Replay of c80d2da0a95a63b76f5a4c835f1a0e1022ec2f53) --- modules/gallery/models/item.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 430119b5..7dbbbcb1 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -389,8 +389,7 @@ class Item_Model extends ORM_MPTT { SELECT COUNT(*) AS position FROM {items} WHERE parent_id = {$this->id} AND `{$this->sort_column}` $comp (SELECT `{$this->sort_column}` - FROM {items} WHERE id = $child_id) - ORDER BY `{$this->sort_column}` {$this->sort_order}")->current()->position; + FROM {items} WHERE id = $child_id)")->current()->position; // We stopped short of our target value in the sort (notice that we're using a < comparator // above) because it's possible that we have duplicate values in the sort column. An -- cgit v1.2.3 From 923732ca4dca6db218f6252a7133cd72f98fa086 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Thu, 25 Jun 2009 10:07:12 +0200 Subject: Go back to the upstream version because we choosed to use real booleans. --- modules/gallery/helpers/access.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index 7b01058c..c48f0b79 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -426,7 +426,7 @@ class access_Core { $field = "{$perm_name}_{$group->id}"; $cache_table = $perm_name == "view" ? "items" : "access_caches"; $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0"); - $db->query("ALTER TABLE {access_intents} ADD `$field` SMALLINT DEFAULT NULL"); + $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL"); $db->update("access_intents", array($field => 0), array("item_id" => 1)); ORM::factory("access_intent")->clear_cache(); } -- cgit v1.2.3 From c4fce2cc680c3257cf6ea7844b8ee9e61c02db09 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 15 Jul 2009 20:32:53 -0700 Subject: Remove a completed @todo. --- modules/gallery/controllers/albums.php | 4 ---- 1 file changed, 4 deletions(-) (limited to 'modules') diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index d141d157..e6d01b90 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -181,10 +181,6 @@ class Albums_Controller extends Items_Controller { } } - // @todo - // @todo we need to make sure that filename / dirname components can't contain a / - // @todo - if ($valid) { $orig = clone $album; $album->title = $form->edit_album->title->value; -- cgit v1.2.3 From 5cb2f42628bdfa66a1a0821efb5f9d8e78f06626 Mon Sep 17 00:00:00 2001 From: Kevin Nehls Date: Wed, 15 Jul 2009 11:41:10 +0800 Subject: Fix backslashes in relative URLs of combined css files. Signed-off-by: Bharat Mediratta --- modules/gallery/libraries/Gallery_View.php | 1 + 1 file changed, 1 insertion(+) (limited to 'modules') diff --git a/modules/gallery/libraries/Gallery_View.php b/modules/gallery/libraries/Gallery_View.php index 8a0be7f2..4715be09 100644 --- a/modules/gallery/libraries/Gallery_View.php +++ b/modules/gallery/libraries/Gallery_View.php @@ -135,6 +135,7 @@ class Gallery_View_Core extends View { $relative = substr(realpath(dirname($css_file) . "/$match[1]"), $docroot_length); if (!empty($relative)) { $search[] = $match[0]; + $relative = str_replace(DIRECTORY_SEPARATOR, "/", $relative); $replace[] = "url('" . url::abs_file($relative) . "')"; } else { Kohana::log("error", "Missing URL reference '{$match[1]}' in CSS file '$css_file'"); -- cgit v1.2.3 From 85b0f580291e375a2c5ec21b8210e59023ee24c2 Mon Sep 17 00:00:00 2001 From: Kevin Nehls Date: Thu, 16 Jul 2009 12:28:00 +0800 Subject: move fix for backslashes on windows outside of loop per bharat's suggestion Signed-off-by: Bharat Mediratta --- modules/gallery/libraries/Gallery_View.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/libraries/Gallery_View.php b/modules/gallery/libraries/Gallery_View.php index 4715be09..133066d7 100644 --- a/modules/gallery/libraries/Gallery_View.php +++ b/modules/gallery/libraries/Gallery_View.php @@ -135,12 +135,12 @@ class Gallery_View_Core extends View { $relative = substr(realpath(dirname($css_file) . "/$match[1]"), $docroot_length); if (!empty($relative)) { $search[] = $match[0]; - $relative = str_replace(DIRECTORY_SEPARATOR, "/", $relative); $replace[] = "url('" . url::abs_file($relative) . "')"; } else { Kohana::log("error", "Missing URL reference '{$match[1]}' in CSS file '$css_file'"); } } + $replace = str_replace(DIRECTORY_SEPARATOR, "/", $replace); $css = str_replace($search, $replace, $css); } $imports = preg_match_all("#@import\s*['|\"]{0,1}(.*?)['|\"]{0,1};#", -- cgit v1.2.3 From b46998e392bbf52fadc9c8e13271d911dff01cbe Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 10:24:10 -0700 Subject: Update Xss_Security_Test to know about p::purify() and checkpoint the golden file. --- modules/gallery/tests/Xss_Security_Test.php | 2 +- modules/gallery/tests/xss_data.txt | 93 ++++++++++++++++------------- 2 files changed, 51 insertions(+), 44 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index e179482c..9bde11dc 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -36,7 +36,7 @@ class Xss_Security_Test extends Unit_Test_Case { // 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") { + if ($token[0] == "(" && ($str == "p::clean" || $str == "p::purify")) { $in_p_clean = 1; } else if ($token[0] == "(" && $in_p_clean) { $in_p_clean++; diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 982343f6..d1167555 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -141,22 +141,28 @@ modules/gallery/views/admin_maintenance.html.php 75 DIRTY $task->na modules/gallery/views/admin_maintenance.html.php 86 DIRTY $task->percent_complete modules/gallery/views/admin_maintenance.html.php 90 DIRTY $task->status modules/gallery/views/admin_maintenance.html.php 93 $task->owner()->name -modules/gallery/views/admin_maintenance.html.php 97 DIRTY $task->id -modules/gallery/views/admin_maintenance.html.php 97 DIRTY $csrf -modules/gallery/views/admin_maintenance.html.php 101 DIRTY $task->id -modules/gallery/views/admin_maintenance.html.php 101 DIRTY $csrf -modules/gallery/views/admin_maintenance.html.php 113 DIRTY $csrf -modules/gallery/views/admin_maintenance.html.php 140 DIRTY $task->state -modules/gallery/views/admin_maintenance.html.php 142 DIRTY $task->updated -modules/gallery/views/admin_maintenance.html.php 145 DIRTY $task->name -modules/gallery/views/admin_maintenance.html.php 157 DIRTY $task->status -modules/gallery/views/admin_maintenance.html.php 160 DIRTY $task->owner()->name -modules/gallery/views/admin_maintenance.html.php 164 DIRTY $task->id -modules/gallery/views/admin_maintenance.html.php 164 DIRTY $csrf -modules/gallery/views/admin_maintenance.html.php 168 DIRTY $task->id -modules/gallery/views/admin_maintenance.html.php 168 DIRTY $csrf -modules/gallery/views/admin_maintenance.html.php 171 DIRTY $task->id -modules/gallery/views/admin_maintenance.html.php 171 DIRTY $csrf +modules/gallery/views/admin_maintenance.html.php 98 DIRTY $task->id +modules/gallery/views/admin_maintenance.html.php 98 DIRTY $csrf +modules/gallery/views/admin_maintenance.html.php 102 DIRTY $task->id +modules/gallery/views/admin_maintenance.html.php 102 DIRTY $csrf +modules/gallery/views/admin_maintenance.html.php 115 DIRTY $csrf +modules/gallery/views/admin_maintenance.html.php 142 DIRTY $task->state +modules/gallery/views/admin_maintenance.html.php 144 DIRTY $task->updated +modules/gallery/views/admin_maintenance.html.php 147 DIRTY $task->name +modules/gallery/views/admin_maintenance.html.php 159 DIRTY $task->status +modules/gallery/views/admin_maintenance.html.php 162 DIRTY $task->owner()->name +modules/gallery/views/admin_maintenance.html.php 166 DIRTY $task->id +modules/gallery/views/admin_maintenance.html.php 166 DIRTY $csrf +modules/gallery/views/admin_maintenance.html.php 170 DIRTY $task->id +modules/gallery/views/admin_maintenance.html.php 170 DIRTY $csrf +modules/gallery/views/admin_maintenance.html.php 175 DIRTY $task->id +modules/gallery/views/admin_maintenance.html.php 175 DIRTY $csrf +modules/gallery/views/admin_maintenance.html.php 178 DIRTY $task->id +modules/gallery/views/admin_maintenance.html.php 178 DIRTY $csrf +modules/gallery/views/admin_maintenance_show_log.html.php 8 DIRTY $task->id +modules/gallery/views/admin_maintenance_show_log.html.php 8 DIRTY $csrf +modules/gallery/views/admin_maintenance_show_log.html.php 13 DIRTY $task->name +modules/gallery/views/admin_maintenance_show_log.html.php 15 $task->get_log() modules/gallery/views/admin_maintenance_task.html.php 5 DIRTY $task->id modules/gallery/views/admin_maintenance_task.html.php 5 DIRTY $csrf modules/gallery/views/admin_maintenance_task.html.php 26 DIRTY $task->name @@ -201,10 +207,10 @@ modules/gallery/views/admin_themes_preview.html.php 4 DIRTY $info->na modules/gallery/views/admin_themes_preview.html.php 7 DIRTY $url modules/gallery/views/after_install.html.php 11 $user->name modules/gallery/views/after_install.html.php 15 DIRTY $user->id -modules/gallery/views/kohana_error_page.php 98 DIRTY $message -modules/gallery/views/kohana_error_page.php 100 DIRTY $file -modules/gallery/views/kohana_error_page.php 100 DIRTY $line -modules/gallery/views/kohana_error_page.php 112 DIRTY $trace +modules/gallery/views/kohana_error_page.php 102 DIRTY $message +modules/gallery/views/kohana_error_page.php 104 DIRTY $file +modules/gallery/views/kohana_error_page.php 104 DIRTY $line +modules/gallery/views/kohana_error_page.php 116 DIRTY $trace modules/gallery/views/kohana_profiler.php 32 DIRTY $profile->render() modules/gallery/views/kohana_profiler.php 34 DIRTY $execution_time modules/gallery/views/l10n_client.html.php 17 DIRTY $string @@ -212,8 +218,8 @@ modules/gallery/views/l10n_client.html.php 19 DIRTY $string modules/gallery/views/l10n_client.html.php 20 DIRTY $string modules/gallery/views/l10n_client.html.php 22 DIRTY $string modules/gallery/views/l10n_client.html.php 28 DIRTY $l10n_search_form -modules/gallery/views/l10n_client.html.php 72 DIRTY $string_list -modules/gallery/views/l10n_client.html.php 73 DIRTY $plural_forms +modules/gallery/views/l10n_client.html.php 74 DIRTY $string_list +modules/gallery/views/l10n_client.html.php 75 DIRTY $plural_forms modules/gallery/views/move_browse.html.php 4 DIRTY $source->id modules/gallery/views/move_browse.html.php 39 DIRTY $tree modules/gallery/views/move_browse.html.php 42 DIRTY $source->id @@ -280,8 +286,8 @@ modules/gallery/views/simple_uploader.html.php 7 DIRTY $csrf modules/gallery/views/simple_uploader.html.php 9 $item->title modules/gallery/views/simple_uploader.html.php 29 $parent->title modules/gallery/views/simple_uploader.html.php 31 $item->title -modules/gallery/views/simple_uploader.html.php 85 DIRTY $item->id -modules/gallery/views/simple_uploader.html.php 89 DIRTY $csrf +modules/gallery/views/simple_uploader.html.php 86 DIRTY $item->id +modules/gallery/views/simple_uploader.html.php 90 DIRTY $csrf modules/gallery/views/upgrader.html.php 44 DIRTY $module->version modules/gallery/views/upgrader.html.php 44 DIRTY $module->code_version modules/gallery/views/upgrader.html.php 45 DIRTY $id @@ -417,16 +423,17 @@ modules/server_add/views/admin_server_add.html.php 14 DIRTY $csrf modules/server_add/views/admin_server_add.html.php 15 DIRTY $id modules/server_add/views/admin_server_add.html.php 19 DIRTY $path modules/server_add/views/admin_server_add.html.php 24 DIRTY $form -modules/server_add/views/server_add_tree.html.php 4 DIRTY $tree_id -modules/server_add/views/server_add_tree.html.php 6 DIRTY $file_info -modules/server_add/views/server_add_tree.html.php 10 $file_info -modules/server_add/views/server_add_tree.html.php 10 DIRTY $checked -modules/server_add/views/server_add_tree.html.php 10 $file -modules/server_add/views/server_add_tree_dialog.html.php 10 $album_title -modules/server_add/views/server_add_tree_dialog.html.php 15 $parent->title -modules/server_add/views/server_add_tree_dialog.html.php 17 $album_title -modules/server_add/views/server_add_tree_dialog.html.php 20 DIRTY $action -modules/server_add/views/server_add_tree_dialog.html.php 22 DIRTY $tree +modules/server_add/views/server_add_tree.html.php 12 DIRTY $dir +modules/server_add/views/server_add_tree.html.php 13 DIRTY $dir +modules/server_add/views/server_add_tree.html.php 20 DIRTY $file +modules/server_add/views/server_add_tree.html.php 25 DIRTY $file +modules/server_add/views/server_add_tree.html.php 27 $file +modules/server_add/views/server_add_tree_dialog.html.php 4 DIRTY $item->id +modules/server_add/views/server_add_tree_dialog.html.php 4 DIRTY $csrf +modules/server_add/views/server_add_tree_dialog.html.php 8 $item->title +modules/server_add/views/server_add_tree_dialog.html.php 14 $parent->title +modules/server_add/views/server_add_tree_dialog.html.php 18 $item->title +modules/server_add/views/server_add_tree_dialog.html.php 23 DIRTY $tree modules/tag/views/admin_tags.html.php 13 DIRTY $csrf modules/tag/views/admin_tags.html.php 27 DIRTY $tags->count() modules/tag/views/admin_tags.html.php 35 DIRTY $current_letter @@ -501,14 +508,14 @@ themes/admin_default/views/admin.html.php 37 DIRTY $theme->a themes/admin_default/views/admin.html.php 43 DIRTY $theme->site_status() themes/admin_default/views/admin.html.php 45 DIRTY $theme->admin_header_top() themes/admin_default/views/admin.html.php 48 DIRTY $csrf -themes/admin_default/views/admin.html.php 52 DIRTY $theme->admin_menu() -themes/admin_default/views/admin.html.php 54 DIRTY $theme->admin_header_bottom() -themes/admin_default/views/admin.html.php 60 DIRTY $theme->messages() -themes/admin_default/views/admin.html.php 61 DIRTY $content -themes/admin_default/views/admin.html.php 67 DIRTY $sidebar -themes/admin_default/views/admin.html.php 72 DIRTY $theme->admin_footer() -themes/admin_default/views/admin.html.php 74 DIRTY $theme->admin_credits() -themes/admin_default/views/admin.html.php 78 DIRTY $theme->admin_page_bottom() +themes/admin_default/views/admin.html.php 54 DIRTY $theme->admin_menu() +themes/admin_default/views/admin.html.php 56 DIRTY $theme->admin_header_bottom() +themes/admin_default/views/admin.html.php 62 DIRTY $theme->messages() +themes/admin_default/views/admin.html.php 63 DIRTY $content +themes/admin_default/views/admin.html.php 69 DIRTY $sidebar +themes/admin_default/views/admin.html.php 74 DIRTY $theme->admin_footer() +themes/admin_default/views/admin.html.php 76 DIRTY $theme->admin_credits() +themes/admin_default/views/admin.html.php 80 DIRTY $theme->admin_page_bottom() themes/admin_default/views/block.html.php 2 DIRTY $id themes/admin_default/views/block.html.php 2 DIRTY $css_id themes/admin_default/views/block.html.php 5 DIRTY $id @@ -544,7 +551,7 @@ themes/default/views/block.html.php 3 DIRTY $css_id themes/default/views/block.html.php 4 DIRTY $title themes/default/views/block.html.php 6 DIRTY $content themes/default/views/dynamic.html.php 4 DIRTY $theme->dynamic_top() -themes/default/views/dynamic.html.php 6 $tag->name +themes/default/views/dynamic.html.php 6 $title themes/default/views/dynamic.html.php 11 DIRTY $child->is_album() themes/default/views/dynamic.html.php 12 DIRTY $theme->thumb_top($child) themes/default/views/dynamic.html.php 13 DIRTY $child->url() -- cgit v1.2.3 From d9f3e0bc0e6e7e21025f65ec34c83717af47ba9b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 10:27:18 -0700 Subject: Remove spurious blank line at the top of the file introduced in 09c9b1a75561881a40ada71f02710355923602e2 --- modules/gallery/controllers/simple_uploader.php | 1 - 1 file changed, 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/controllers/simple_uploader.php b/modules/gallery/controllers/simple_uploader.php index 75a7b810..e7c0bd6f 100644 --- a/modules/gallery/controllers/simple_uploader.php +++ b/modules/gallery/controllers/simple_uploader.php @@ -1,4 +1,3 @@ - Date: Thu, 16 Jul 2009 10:32:18 -0700 Subject: Remove trailing ?>. --- .../lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'modules') diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php index 731c3171..81305bcf 100644 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php +++ b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php @@ -3,7 +3,7 @@ /** * Experimental HTML5-based parser using Jeroen van der Meer's PH5P library. * Occupies space in the HTML5 pseudo-namespace, which may cause conflicts. - * + * * @note * Recent changes to PHP's DOM extension have resulted in some fatal * error conditions with the original version of PH5P. Pending changes, @@ -11,7 +11,7 @@ */ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex { - + public function tokenizeHTML($html, $config, $context) { $new_html = $this->normalize($html, $config, $context); $new_html = $this->wrapHTML($new_html, $config, $context); @@ -32,31 +32,31 @@ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex { , $tokens); return $tokens; } - + } /* -Copyright 2007 Jeroen van der Meer +Copyright 2007 Jeroen van der Meer -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ @@ -1075,7 +1075,7 @@ class HTML5 { // used when parsing entities in text and in attributes. // The behaviour depends on the identity of the next character (the - // one immediately after the U+0026 AMPERSAND character): + // one immediately after the U+0026 AMPERSAND character): switch($this->character($this->char + 1)) { // U+0023 NUMBER SIGN (#) @@ -2231,7 +2231,7 @@ class HTML5TreeConstructer { if($this->elementInScope($token['name'])) { $this->generateImpliedEndTags(); - } + } if(end($this->stack)->nodeName !== $token['name']) { /* Now, if the current node is not an element with the @@ -2610,7 +2610,7 @@ class HTML5TreeConstructer { for($x = count($this->stack) - $n; $x >= $n; $x--) { array_pop($this->stack); } - + } else { $category = $this->getElementCategory($node); @@ -3546,7 +3546,7 @@ class HTML5TreeConstructer { // In theory, this should ever be needed, but just in case if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice } - + $el = $this->dom->createElement($token['name']); foreach($token['attr'] as $attr) { @@ -3903,4 +3903,4 @@ class HTML5TreeConstructer { return $this->dom; } } -?> + -- cgit v1.2.3 From 2cd0d6389c39badc1c3c7963e03f80097eaac3c2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 10:44:23 -0700 Subject: Revert "Remove trailing ?>." This reverts commit a333e01bd1c8cb3ad08cd0ad16023e3fcdfc4181. --- .../lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'modules') diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php index 81305bcf..731c3171 100644 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php +++ b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php @@ -3,7 +3,7 @@ /** * Experimental HTML5-based parser using Jeroen van der Meer's PH5P library. * Occupies space in the HTML5 pseudo-namespace, which may cause conflicts. - * + * * @note * Recent changes to PHP's DOM extension have resulted in some fatal * error conditions with the original version of PH5P. Pending changes, @@ -11,7 +11,7 @@ */ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex { - + public function tokenizeHTML($html, $config, $context) { $new_html = $this->normalize($html, $config, $context); $new_html = $this->wrapHTML($new_html, $config, $context); @@ -32,31 +32,31 @@ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex { , $tokens); return $tokens; } - + } /* -Copyright 2007 Jeroen van der Meer +Copyright 2007 Jeroen van der Meer -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ @@ -1075,7 +1075,7 @@ class HTML5 { // used when parsing entities in text and in attributes. // The behaviour depends on the identity of the next character (the - // one immediately after the U+0026 AMPERSAND character): + // one immediately after the U+0026 AMPERSAND character): switch($this->character($this->char + 1)) { // U+0023 NUMBER SIGN (#) @@ -2231,7 +2231,7 @@ class HTML5TreeConstructer { if($this->elementInScope($token['name'])) { $this->generateImpliedEndTags(); - } + } if(end($this->stack)->nodeName !== $token['name']) { /* Now, if the current node is not an element with the @@ -2610,7 +2610,7 @@ class HTML5TreeConstructer { for($x = count($this->stack) - $n; $x >= $n; $x--) { array_pop($this->stack); } - + } else { $category = $this->getElementCategory($node); @@ -3546,7 +3546,7 @@ class HTML5TreeConstructer { // In theory, this should ever be needed, but just in case if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice } - + $el = $this->dom->createElement($token['name']); foreach($token['attr'] as $attr) { @@ -3903,4 +3903,4 @@ class HTML5TreeConstructer { return $this->dom; } } - +?> -- cgit v1.2.3 From ec634c91a6824185485f9349cfe15d6e759bb23e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 10:45:06 -0700 Subject: Stripped the trailing ?> without changing whitespace. --- modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php index 731c3171..0d20c0ce 100644 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php +++ b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php @@ -3903,4 +3903,4 @@ class HTML5TreeConstructer { return $this->dom; } } -?> + -- cgit v1.2.3 From 2864aceb8117d0644b264ceca4d0f84fd028538f Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 10:58:42 -0700 Subject: Add missing ) dropped in 8f9a943f. --- modules/user/controllers/password.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index ed3b9736..2af1b879 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -74,7 +74,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" => p::clean($user->name)))); } else { // Don't include the username here until you're sure that it's XSS safe log::warning( -- cgit v1.2.3 From 5b3b675b6d8a1cd9a5f2b9455c551791e18d88ff Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 11:19:34 -0700 Subject: Non-trivial changes to the event handling code: 1) The item_updated event no longer takes the old and new items. Instead we overload ORM to track the original data and make that available via the item. This will allow us to move event publishing down into the API methods which in turn will give us more stability since we won't require each controller to remember to do it. 2) ORM class now tracks the original values. It doesn't track the original relationships (no need for that, yet) 3) Added new events: item_deleted group_deleted user_deleted --- modules/akismet/helpers/akismet_event.php | 6 ++--- modules/comment/controllers/admin_comments.php | 4 ++-- modules/comment/helpers/comment_event.php | 2 +- modules/exif/helpers/exif_event.php | 2 +- modules/g2_import/helpers/g2_import_event.php | 2 +- modules/gallery/controllers/albums.php | 2 +- modules/gallery/controllers/movies.php | 2 +- modules/gallery/controllers/photos.php | 2 +- modules/gallery/helpers/gallery_event.php | 4 ++-- modules/gallery/libraries/MY_ORM.php | 27 +++++++++++++++++++++- modules/gallery/models/item.php | 3 +++ modules/gallery/tests/Item_Model_Test.php | 16 +++++++++++++ modules/notification/helpers/notification.php | 19 ++++++++------- .../notification/helpers/notification_event.php | 10 ++++---- modules/notification/helpers/notification_menu.php | 2 +- modules/notification/views/item_updated.html.php | 16 ++++++------- modules/organize/controllers/organize.php | 4 ++-- modules/search/helpers/search_event.php | 6 ++--- modules/tag/helpers/tag_event.php | 2 +- modules/user/models/group.php | 2 ++ modules/user/models/user.php | 2 ++ 21 files changed, 91 insertions(+), 44 deletions(-) (limited to 'modules') diff --git a/modules/akismet/helpers/akismet_event.php b/modules/akismet/helpers/akismet_event.php index 80fe0127..bffc0fd7 100644 --- a/modules/akismet/helpers/akismet_event.php +++ b/modules/akismet/helpers/akismet_event.php @@ -40,14 +40,14 @@ class akismet_event_Core { $comment->save(); } - static function comment_updated($old, $new) { + static function comment_updated($comment) { if (!module::get_var("akismet", "api_key")) { return; } - if ($old->state != "spam" && $new->state == "spam") { + if ($comment->original("state") != "spam" && $comment->state == "spam") { akismet::submit_spam($new); - } else if ($old->state == "spam" && $new->state != "spam") { + } else if ($comment->original("state") == "spam" && $comment->state != "spam") { akismet::submit_ham($new); } } diff --git a/modules/comment/controllers/admin_comments.php b/modules/comment/controllers/admin_comments.php index 3e8d3c46..ea76b188 100644 --- a/modules/comment/controllers/admin_comments.php +++ b/modules/comment/controllers/admin_comments.php @@ -113,8 +113,8 @@ class Admin_Comments_Controller extends Admin_Controller { if ($comment->loaded) { $comment->state = $state; $comment->save(); - module::event("comment_updated", $orig, $comment); - if ($orig->state == "published" || $comment->state == "published") { + module::event("comment_updated", $comment); + if ($comment->original("state") == "published" || $comment->state == "published") { module::event("item_related_update", $comment->item()); } } diff --git a/modules/comment/helpers/comment_event.php b/modules/comment/helpers/comment_event.php index a3beb27a..3850a001 100644 --- a/modules/comment/helpers/comment_event.php +++ b/modules/comment/helpers/comment_event.php @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class comment_event_Core { - static function item_before_delete($item) { + static function item_deleted($item) { Database::instance()->delete("comments", array("item_id" => $item->id)); } } diff --git a/modules/exif/helpers/exif_event.php b/modules/exif/helpers/exif_event.php index f5677653..24243f4d 100644 --- a/modules/exif/helpers/exif_event.php +++ b/modules/exif/helpers/exif_event.php @@ -22,7 +22,7 @@ class exif_event_Core { exif::extract($item); } - static function item_before_delete($item) { + static function item_deleted($item) { Database::instance()->delete("exif_records", array("item_id" => $item->id)); } } diff --git a/modules/g2_import/helpers/g2_import_event.php b/modules/g2_import/helpers/g2_import_event.php index 13f5b1a0..77b489a7 100644 --- a/modules/g2_import/helpers/g2_import_event.php +++ b/modules/g2_import/helpers/g2_import_event.php @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class g2_import_event_Core { - static function item_before_delete($item) { + static function item_deleted($item) { Database::instance()->delete("g2_maps", array("g3_id" => $item->id)); } diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index e6d01b90..c378e3ce 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -192,7 +192,7 @@ class Albums_Controller extends Items_Controller { } $album->save(); - module::event("item_updated", $orig, $album); + module::event("item_updated", $album); log::success("content", "Updated album", "id\">view"); message::success( diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php index 30a5d78c..fc511082 100644 --- a/modules/gallery/controllers/movies.php +++ b/modules/gallery/controllers/movies.php @@ -91,7 +91,7 @@ class Movies_Controller extends Items_Controller { $photo->rename($form->edit_photo->filename->value); $photo->save(); - module::event("item_updated", $orig, $photo); + module::event("item_updated", $photo); log::success("content", "Updated photo", "id\">view"); message::success( diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php index 6a62e859..77627009 100644 --- a/modules/gallery/controllers/photos.php +++ b/modules/gallery/controllers/photos.php @@ -84,7 +84,7 @@ class Photos_Controller extends Items_Controller { $photo->rename($form->edit_photo->filename->value); $photo->save(); - module::event("item_updated", $orig, $photo); + module::event("item_updated", $photo); log::success("content", "Updated photo", "id\">view"); message::success( diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index aa11b7c0..2f3a64d3 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -23,7 +23,7 @@ class gallery_event_Core { access::add_group($group); } - static function group_before_delete($group) { + static function group_deleted($group) { access::delete_group($group); } @@ -31,7 +31,7 @@ class gallery_event_Core { access::add_item($item); } - static function item_before_delete($item) { + static function item_deleted($item) { access::delete_item($item); } diff --git a/modules/gallery/libraries/MY_ORM.php b/modules/gallery/libraries/MY_ORM.php index 2bd9b4eb..319cbe09 100644 --- a/modules/gallery/libraries/MY_ORM.php +++ b/modules/gallery/libraries/MY_ORM.php @@ -18,6 +18,9 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class ORM extends ORM_Core { + // Track the original value of this ORM instance so that we can look it up in ORM::original() + protected $original = null; + public function open_paren() { $this->db->open_paren(); return $this; @@ -30,7 +33,29 @@ class ORM extends ORM_Core { public function save() { model_cache::clear($this->object_name, $this->{$this->primary_key}, $this->primary_key); - return parent::save(); + $result = parent::save(); + $this->original = $this->object; + return $result; + } + + public function __set($column, $value) { + if (!isset($this->original)) { + $this->original = $this->object; + } + + return parent::__set($column, $value); + } + + public function __unset($column) { + if (!isset($this->original)) { + $this->original = $this->object; + } + + return parent::__unset($column); + } + + public function original($column) { + return $this->original[$column]; } } diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 51037073..80f19d26 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -93,6 +93,7 @@ class Item_Model extends ORM_MPTT { } public function delete() { + $old = clone $this; module::event("item_before_delete", $this); $parent = $this->parent(); @@ -114,6 +115,8 @@ class Item_Model extends ORM_MPTT { @unlink($resize_path); @unlink($thumb_path); } + + module::event("item_deleted", $old); } /** diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php index 615b8997..a21cdc13 100644 --- a/modules/gallery/tests/Item_Model_Test.php +++ b/modules/gallery/tests/Item_Model_Test.php @@ -140,4 +140,20 @@ class Item_Model_Test extends Unit_Test_Case { } $this->assert_false(true, "Item_Model::rename should not accept / characters"); } + + public function save_original_values_test() { + print "START\n"; + $item = $this->create_random_item(); + $item->title = "ORIGINAL_VALUE"; + $item->save(); + + print "CHANGE\n"; + $item->title = "NEW_VALUE"; + + //printf("
%s
",print_r($item,1));flush(); + + print "COMPARE\n"; + $this->assert_same("ORIGINAL_VALUE", $item->original("title")); + $this->assert_same("NEW_VALUE", $item->title); + } } diff --git a/modules/notification/helpers/notification.php b/modules/notification/helpers/notification.php index 8ee0c6ba..e246af2c 100644 --- a/modules/notification/helpers/notification.php +++ b/modules/notification/helpers/notification.php @@ -82,17 +82,16 @@ class notification { return $subscribers; } - static function send_item_updated($old, $new) { + static function send_item_updated($item) { $v = new View("item_updated.html"); - $v->old = $old; - $v->new = $new; - $v->subject = $old->is_album() ? - t("Album %title updated", array("title" => $old->title)) : - ($old->is_photo() ? - t("Photo %title updated", array("title" => $old->title)) - : t("Movie %title updated", array("title" => $old->title))); - - self::_notify_subscribers($old, $v->render(), $v->subject); + $v->item = $item; + $v->subject = $item->is_album() ? + t("Album %title updated", array("title" => $item->original("title"))) : + ($item->is_photo() ? + t("Photo %title updated", array("title" => $item->original("title"))) + : t("Movie %title updated", array("title" => $item->original("title")))); + + self::_notify_subscribers($item, $v->render(), $v->subject); } static function send_item_add($item) { diff --git a/modules/notification/helpers/notification_event.php b/modules/notification/helpers/notification_event.php index 1cf9ff58..536557c6 100644 --- a/modules/notification/helpers/notification_event.php +++ b/modules/notification/helpers/notification_event.php @@ -18,15 +18,15 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class notification_event_Core { - static function item_updated($old, $new) { - notification::send_item_updated($old, $new); + static function item_updated($item) { + notification::send_item_updated($item); } static function item_created($item) { notification::send_item_add($item); } - static function item_before_delete($item) { + static function item_deleted($item) { notification::send_item_deleted($item); if (notification::is_watching($item)) { @@ -40,8 +40,8 @@ class notification_event_Core { } } - static function comment_updated($old, $new) { - if ($new->state == "published" && $old->state != "published") { + static function comment_updated($item) { + if ($item->state == "published" && $item->original("state") != "published") { notification::send_comment_published($new); } } diff --git a/modules/notification/helpers/notification_menu.php b/modules/notification/helpers/notification_menu.php index 696aad62..87478b8a 100644 --- a/modules/notification/helpers/notification_menu.php +++ b/modules/notification/helpers/notification_menu.php @@ -21,7 +21,7 @@ class notification_menu_Core { static function site($menu, $theme) { if (!user::active()->guest) { $item = $theme->item(); - + if ($item && $item->is_album()) { $watching = notification::is_watching($item); diff --git a/modules/notification/views/item_updated.html.php b/modules/notification/views/item_updated.html.php index 0620c50c..39f9113b 100644 --- a/modules/notification/views/item_updated.html.php +++ b/modules/notification/views/item_updated.html.php @@ -7,27 +7,27 @@

- title != $new->title): ?> + original("title") != $item->title): ?> - + - + - + - description != $new->description): ?> + original("description") != $item->description): ?> - + - description)): ?> + description)): ?> - +
title) ?>title) ?> title) ?>title) ?>
url(array(), true) ?>url(array(), true) ?>
description) ?>description) ?>
description) ?>description) ?>
diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 6792573d..54e04071 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -279,7 +279,7 @@ class Organize_Controller extends Controller { $item->rename($form->dirname->value); $item->save(); - module::event("item_updated", $orig, $item); + module::event("item_updated", $item); if ($item->is_album()) { log::success("content", "Updated album", "id\">view"); @@ -322,7 +322,7 @@ class Organize_Controller extends Controller { $item->sort_order = $form->direction->value; $item->save(); - module::event("item_updated", $orig, $item); + module::event("item_updated", $item); log::success("content", "Updated album", "id\">view"); $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); diff --git a/modules/search/helpers/search_event.php b/modules/search/helpers/search_event.php index b9657395..764fdd18 100644 --- a/modules/search/helpers/search_event.php +++ b/modules/search/helpers/search_event.php @@ -22,11 +22,11 @@ class search_event_Core { search::update($item); } - static function item_updated($old_item, $new_item) { - search::update($new_item); + static function item_updated($item) { + search::update($item); } - static function item_before_delete($item) { + static function item_deleted($item) { ORM::factory("search_record") ->where("item_id", $item->id) ->delete_all(); diff --git a/modules/tag/helpers/tag_event.php b/modules/tag/helpers/tag_event.php index 7a170bf8..0164f556 100644 --- a/modules/tag/helpers/tag_event.php +++ b/modules/tag/helpers/tag_event.php @@ -59,7 +59,7 @@ class tag_event_Core { return; } - static function item_before_delete($item) { + static function item_deleted($item) { $db = Database::instance(); $db->query("UPDATE {tags} SET `count` = `count` - 1 WHERE `count` > 0 " . "AND `id` IN (SELECT `tag_id` from {items_tags} WHERE `item_id` = $item->id)"); diff --git a/modules/user/models/group.php b/modules/user/models/group.php index 45948887..e0724e30 100644 --- a/modules/user/models/group.php +++ b/modules/user/models/group.php @@ -27,7 +27,9 @@ class Group_Model extends ORM { * @see ORM::delete() */ public function delete($id=null) { + $old = clone $this; module::event("group_before_delete", $this); parent::delete($id); + module::event("group_deleted", $old); } } \ No newline at end of file diff --git a/modules/user/models/user.php b/modules/user/models/user.php index b447892e..e3260270 100644 --- a/modules/user/models/user.php +++ b/modules/user/models/user.php @@ -44,8 +44,10 @@ class User_Model extends ORM { * @see ORM::delete() */ public function delete($id=null) { + $old = clone $this; module::event("user_before_delete", $this); parent::delete($id); + module::event("user_deleted", $old); } /** -- cgit v1.2.3 From 43324fd12a23b35707300ff110f207552c3811f1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 12:29:01 -0700 Subject: Update golden file to match recent changes in event code. --- modules/gallery/tests/xss_data.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index d1167555..e6f3721b 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -326,12 +326,12 @@ modules/notification/views/item_deleted.html.php 18 DIRTY $item->pa modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->url(array(), true) modules/notification/views/item_updated.html.php 4 $subject modules/notification/views/item_updated.html.php 7 $subject -modules/notification/views/item_updated.html.php 12 $new->title -modules/notification/views/item_updated.html.php 15 $new->title -modules/notification/views/item_updated.html.php 20 DIRTY $new->url(array(), true) -modules/notification/views/item_updated.html.php 20 DIRTY $new->url(array(), true) -modules/notification/views/item_updated.html.php 25 $new->description -modules/notification/views/item_updated.html.php 30 $new->description +modules/notification/views/item_updated.html.php 12 $item->title +modules/notification/views/item_updated.html.php 15 $item->title +modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(), true) +modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(), true) +modules/notification/views/item_updated.html.php 25 $item->description +modules/notification/views/item_updated.html.php 30 $item->description modules/organize/views/organize.html.php 10 DIRTY $item->id modules/organize/views/organize.html.php 12 DIRTY $csrf modules/organize/views/organize.html.php 13 DIRTY $csrf -- cgit v1.2.3 From 0f766b149d0cee7af664f2321fddc6f04cda70ac Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 16 Jul 2009 12:29:16 -0700 Subject: Second non-trivial change to the event code. We now publish model related events from within the model handling code. The only exception to this currently is item_created which is challenging because we have to save the item using ORM_MPTT::add_to_parent() before the object itself is fully set up. When we get that down to one call to save() we can publish that event from within the model also. --- modules/comment/controllers/admin_comments.php | 4 ---- modules/comment/controllers/comments.php | 1 - modules/comment/helpers/comment.php | 5 ----- modules/comment/models/comment.php | 17 ++++++++++++++++- modules/exif/helpers/exif_event.php | 4 +++- modules/gallery/controllers/albums.php | 3 --- modules/gallery/controllers/movies.php | 3 --- modules/gallery/controllers/photos.php | 3 --- modules/gallery/helpers/album.php | 2 ++ modules/gallery/helpers/movie.php | 2 ++ modules/gallery/helpers/photo.php | 2 ++ modules/gallery/models/item.php | 7 ++++++- modules/organize/controllers/organize.php | 4 ---- modules/user/helpers/group.php | 1 - modules/user/helpers/user.php | 1 - modules/user/models/group.php | 13 +++++++++++++ modules/user/models/user.php | 13 +++++++++++++ 17 files changed, 57 insertions(+), 28 deletions(-) (limited to 'modules') diff --git a/modules/comment/controllers/admin_comments.php b/modules/comment/controllers/admin_comments.php index ea76b188..a164f79f 100644 --- a/modules/comment/controllers/admin_comments.php +++ b/modules/comment/controllers/admin_comments.php @@ -113,10 +113,6 @@ class Admin_Comments_Controller extends Admin_Controller { if ($comment->loaded) { $comment->state = $state; $comment->save(); - module::event("comment_updated", $comment); - if ($comment->original("state") == "published" || $comment->state == "published") { - module::event("item_related_update", $comment->item()); - } } } diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php index 02c38491..9fb4796e 100644 --- a/modules/comment/controllers/comments.php +++ b/modules/comment/controllers/comments.php @@ -152,7 +152,6 @@ class Comments_Controller extends REST_Controller { $comment->url = $form->edit_comment->url->value; $comment->text = $form->edit_comment->text->value; $comment->save(); - module::event("comment_updated", $comment); print json_encode( array("result" => "success", diff --git a/modules/comment/helpers/comment.php b/modules/comment/helpers/comment.php index 08cba096..3d743325 100644 --- a/modules/comment/helpers/comment.php +++ b/modules/comment/helpers/comment.php @@ -61,11 +61,6 @@ class comment_Core { $comment->server_remote_port = substr($input->server("REMOTE_PORT"), 0, 16); $comment->save(); - module::event("comment_created", $comment); - if ($comment->state == "published") { - module::event("item_related_update", $comment->item()); - } - return $comment; } diff --git a/modules/comment/models/comment.php b/modules/comment/models/comment.php index 22c465df..551fb245 100644 --- a/modules/comment/models/comment.php +++ b/modules/comment/models/comment.php @@ -61,8 +61,23 @@ class Comment_Model extends ORM { $this->updated = time(); if (!$this->loaded && empty($this->created)) { $this->created = $this->updated; + $created = true; } } - return parent::save(); + parent::save(); + + if (isset($created)) { + module::event("comment_created", $this); + } else { + module::event("comment_updated", $this); + } + + // We only notify on the related items if we're making a visible change, which means moving in + // or out of a published state + if ($this->original("state") == "published" || $this->state == "published") { + module::event("item_related_update", $this->item()); + } + + return $this; } } diff --git a/modules/exif/helpers/exif_event.php b/modules/exif/helpers/exif_event.php index 24243f4d..826ec959 100644 --- a/modules/exif/helpers/exif_event.php +++ b/modules/exif/helpers/exif_event.php @@ -19,7 +19,9 @@ */ class exif_event_Core { static function item_created($item) { - exif::extract($item); + if (!$item->is_album()) { + exif::extract($item); + } } static function item_deleted($item) { diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index c378e3ce..9980b676 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -182,7 +182,6 @@ class Albums_Controller extends Items_Controller { } if ($valid) { - $orig = clone $album; $album->title = $form->edit_album->title->value; $album->description = $form->edit_album->description->value; $album->sort_column = $form->edit_album->sort_order->column->value; @@ -192,8 +191,6 @@ class Albums_Controller extends Items_Controller { } $album->save(); - module::event("item_updated", $album); - log::success("content", "Updated album", "id\">view"); message::success( t("Saved album %album_title", array("album_title" => p::clean($album->title)))); diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php index fc511082..d954ad8d 100644 --- a/modules/gallery/controllers/movies.php +++ b/modules/gallery/controllers/movies.php @@ -85,14 +85,11 @@ class Movies_Controller extends Items_Controller { } if ($valid) { - $orig = clone $photo; $photo->title = $form->edit_photo->title->value; $photo->description = $form->edit_photo->description->value; $photo->rename($form->edit_photo->filename->value); $photo->save(); - module::event("item_updated", $photo); - log::success("content", "Updated photo", "id\">view"); message::success( t("Saved photo %photo_title", array("photo_title" => p::clean($photo->title)))); diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php index 77627009..9ce6ed23 100644 --- a/modules/gallery/controllers/photos.php +++ b/modules/gallery/controllers/photos.php @@ -78,14 +78,11 @@ class Photos_Controller extends Items_Controller { } if ($valid) { - $orig = clone $photo; $photo->title = $form->edit_photo->title->value; $photo->description = $form->edit_photo->description->value; $photo->rename($form->edit_photo->filename->value); $photo->save(); - module::event("item_updated", $photo); - log::success("content", "Updated photo", "id\">view"); message::success( t("Saved photo %photo_title", array("photo_title" => p::clean($photo->title)))); diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index 1197f243..f1a6c060 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -71,6 +71,8 @@ class album_Core { mkdir(dirname($album->thumb_path())); mkdir(dirname($album->resize_path())); + // @todo: publish this from inside Item_Model::save() when we refactor to the point where + // there's only one save() happening here. module::event("item_created", $album); return $album; diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index d62ead76..4f4169d5 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -102,6 +102,8 @@ class movie_Core { copy($filename, $movie->file_path()); + // @todo: publish this from inside Item_Model::save() when we refactor to the point where + // there's only one save() happening here. module::event("item_created", $movie); // Build our thumbnail diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index e8a4f357..ce964c14 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -105,6 +105,8 @@ class photo_Core { copy($filename, $photo->file_path()); + // @todo: publish this from inside Item_Model::save() when we refactor to the point where + // there's only one save() happening here. module::event("item_created", $photo); // Build our thumbnail/resizes diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 80f19d26..94e2fcf7 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -350,9 +350,14 @@ class Item_Model extends ORM_MPTT { $this->created = $this->updated; $r = ORM::factory("item")->select("MAX(weight) as max_weight")->find(); $this->weight = $r->max_weight + 1; + $created = 1; } } - return parent::save(); + parent::save(); + if (!isset($created)) { + module::event("item_updated", $this); + } + return $this; } /** diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 54e04071..27852904 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -279,8 +279,6 @@ class Organize_Controller extends Controller { $item->rename($form->dirname->value); $item->save(); - module::event("item_updated", $item); - if ($item->is_album()) { log::success("content", "Updated album", "id\">view"); $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); @@ -322,8 +320,6 @@ class Organize_Controller extends Controller { $item->sort_order = $form->direction->value; $item->save(); - module::event("item_updated", $item); - log::success("content", "Updated album", "id\">view"); $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); print json_encode(array("form" => $form->__toString(), "message" => $message)); diff --git a/modules/user/helpers/group.php b/modules/user/helpers/group.php index 1dace840..04e6efd6 100644 --- a/modules/user/helpers/group.php +++ b/modules/user/helpers/group.php @@ -39,7 +39,6 @@ class group_Core { $group->name = $name; $group->save(); - module::event("group_created", $group); return $group; } diff --git a/modules/user/helpers/user.php b/modules/user/helpers/user.php index a59588f8..4105d745 100644 --- a/modules/user/helpers/user.php +++ b/modules/user/helpers/user.php @@ -202,7 +202,6 @@ class user_Core { $user->add(group::registered_users()); $user->save(); - module::event("user_created", $user); return $user; } diff --git a/modules/user/models/group.php b/modules/user/models/group.php index e0724e30..bb3fb58b 100644 --- a/modules/user/models/group.php +++ b/modules/user/models/group.php @@ -32,4 +32,17 @@ class Group_Model extends ORM { parent::delete($id); module::event("group_deleted", $old); } + + public function save() { + if (!$this->loaded) { + $created = 1; + } + parent::save(); + if (isset($created)) { + module::event("group_created", $this); + } else { + module::event("group_updated", $this); + } + return $this; + } } \ No newline at end of file diff --git a/modules/user/models/user.php b/modules/user/models/user.php index e3260270..0234f186 100644 --- a/modules/user/models/user.php +++ b/modules/user/models/user.php @@ -59,4 +59,17 @@ class User_Model extends ORM { return sprintf("http://www.gravatar.com/avatar/%s.jpg?s=%d&r=pg%s", md5($this->email), $size, $default ? "&d=" . urlencode($default) : ""); } + + public function save() { + if (!$this->loaded) { + $created = 1; + } + parent::save(); + if (isset($created)) { + module::event("user_created", $this); + } else { + module::event("user_updated", $this); + } + return $this; + } } \ No newline at end of file -- cgit v1.2.3 From 8a6556b30bc34d69284df6246f4010a8835f3bc2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 17 Jul 2009 08:14:08 -0700 Subject: Fix a bug where moved items don't properly inherit permissions from their new target. After each move, recalculate the permissions for the new parent's hierarchy. Fixes ticket #552 --- modules/gallery/helpers/access.php | 15 ++++++++++++ modules/gallery/helpers/gallery_event.php | 4 ++++ modules/gallery/models/item.php | 6 +++-- modules/gallery/tests/Access_Helper_Test.php | 36 ++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index c48f0b79..5dd1e465 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -243,6 +243,21 @@ class access_Core { self::_set($group, $perm_name, $item, null); } + /** + * Recalculate the permissions for a given item and its hierarchy. $item must be an album. + */ + static function recalculate_permissions($item) { + foreach (self::_get_all_groups() as $group) { + foreach (ORM::factory("permission")->find_all() as $perm) { + if ($perm->name == "view") { + self::_update_access_view_cache($group, $item); + } else { + self::_update_access_non_view_cache($group, $perm->name, $item); + } + } + } + } + /** * Register a permission so that modules can use it. * diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 2f3a64d3..1cd96372 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -35,6 +35,10 @@ class gallery_event_Core { access::delete_item($item); } + static function item_moved($item, $old_parent) { + access::recalculate_permissions($item->parent()); + } + static function user_login($user) { // If this user is an admin, check to see if there are any post-install tasks that we need // to run and take care of those now. diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 94e2fcf7..6512e9e5 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -122,8 +122,8 @@ class Item_Model extends ORM_MPTT { /** * Move this item to the specified target. * @chainable - * @param Item_Model $target Target item (must be an album - * @return ORM_MTPP + * @param Item_Model $target Target item (must be an album) + * @return ORM_MPTT */ function move_to($target) { if (!$target->is_album()) { @@ -137,6 +137,7 @@ class Item_Model extends ORM_MPTT { $original_path = $this->file_path(); $original_resize_path = $this->resize_path(); $original_thumb_path = $this->thumb_path(); + $original_parent = $this->parent(); parent::move_to($target, true); $this->relative_path_cache = null; @@ -154,6 +155,7 @@ class Item_Model extends ORM_MPTT { @rename($original_thumb_path, $this->thumb_path()); } + module::event("item_moved", $this, $original_parent); return $this; } diff --git a/modules/gallery/tests/Access_Helper_Test.php b/modules/gallery/tests/Access_Helper_Test.php index d71bf971..1352b493 100644 --- a/modules/gallery/tests/Access_Helper_Test.php +++ b/modules/gallery/tests/Access_Helper_Test.php @@ -324,4 +324,40 @@ class Access_Helper_Test extends Unit_Test_Case { $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); } + + public function moved_items_inherit_new_permissions_test() { + user::set_active(user::lookup_by_name("admin")); + + $root = ORM::factory("item", 1); + $public_album = album::create($root, rand(), "public album"); + $public_photo = photo::create($public_album, MODPATH . "gallery/images/gallery.png", "", ""); + access::allow(group::everybody(), "view", $public_album); + + $root->reload(); // Account for MPTT changes + + $private_album = album::create($root, rand(), "private album"); + access::deny(group::everybody(), "view", $private_album); + $private_photo = photo::create($private_album, MODPATH . "gallery/images/gallery.png", "", ""); + + // Make sure that we now have a public photo and private photo. + $this->assert_true(access::group_can(group::everybody(), "view", $public_photo)); + $this->assert_false(access::group_can(group::everybody(), "view", $private_photo)); + + // Swap the photos + item::move($public_photo, $private_album); + $private_album->reload(); // Reload to get new MPTT pointers and cached perms. + $public_album->reload(); + $private_photo->reload(); + $public_photo->reload(); + + item::move($private_photo, $public_album); + $private_album->reload(); // Reload to get new MPTT pointers and cached perms. + $public_album->reload(); + $private_photo->reload(); + $public_photo->reload(); + + // Make sure that the public_photo is now private, and the private_photo is now public. + $this->assert_false(access::group_can(group::everybody(), "view", $public_photo)); + $this->assert_true(access::group_can(group::everybody(), "view", $private_photo)); + } } -- cgit v1.2.3 From cd907c2b42f8b50ebe6d490aab42365e16deb258 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 17 Jul 2009 12:51:27 -0700 Subject: Change model_cache::clear() API to clear everything. This prevents old ORM relationships from hanging around, which was causing problems when doing MPTT manipulations (resulting in incorrect permission propagation-- very bad!) --- modules/gallery/helpers/access.php | 4 ++++ modules/gallery/helpers/item.php | 4 ++-- modules/gallery/helpers/model_cache.php | 6 ++---- modules/gallery/libraries/MY_ORM.php | 2 +- modules/gallery/libraries/ORM_MPTT.php | 1 + modules/gallery/models/item.php | 1 + 6 files changed, 11 insertions(+), 7 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index 5dd1e465..63324e5d 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -205,6 +205,7 @@ class access_Core { } self::_update_htaccess_files($album, $group, $perm_name, $value); + model_cache::clear(); } /** @@ -256,6 +257,7 @@ class access_Core { } } } + model_cache::clear(); } /** @@ -426,6 +428,7 @@ class access_Core { $cache_table = $perm_name == "view" ? "items" : "access_caches"; $db->query("ALTER TABLE {{$cache_table}} DROP `$field`"); $db->query("ALTER TABLE {access_intents} DROP `$field`"); + model_cache::clear(); ORM::factory("access_intent")->clear_cache(); } @@ -443,6 +446,7 @@ class access_Core { $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0"); $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL"); $db->update("access_intents", array($field => 0), array("item_id" => 1)); + model_cache::clear(); ORM::factory("access_intent")->clear_cache(); } diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php index f40b5c97..80c25862 100644 --- a/modules/gallery/helpers/item.php +++ b/modules/gallery/helpers/item.php @@ -53,7 +53,7 @@ class item_Core { access::required("view", $parent); access::required("edit", $parent); - model_cache::clear("item", $parent->album_cover_item_id); + model_cache::clear(); $parent->album_cover_item_id = $item->is_album() ? $item->album_cover_item_id : $item->id; $parent->thumb_dirty = 1; $parent->save(); @@ -69,7 +69,7 @@ class item_Core { access::required("edit", $album); @unlink($album->thumb_path()); - model_cache::clear("item", $album->album_cover_item_id) ; + model_cache::clear(); $album->album_cover_item_id = null; $album->thumb_width = 0; $album->thumb_height = 0; diff --git a/modules/gallery/helpers/model_cache.php b/modules/gallery/helpers/model_cache.php index 2649fdbd..a3e09862 100644 --- a/modules/gallery/helpers/model_cache.php +++ b/modules/gallery/helpers/model_cache.php @@ -32,10 +32,8 @@ class model_cache_Core { return self::$cache->$model_name->$field_name->$id; } - static function clear($model_name, $id, $field_name="id") { - if (!empty(self::$cache->$model_name->$field_name->$id)) { - unset(self::$cache->$model_name->$field_name->$id); - } + static function clear() { + self::$cache = new stdClass(); } static function set($model) { diff --git a/modules/gallery/libraries/MY_ORM.php b/modules/gallery/libraries/MY_ORM.php index 319cbe09..1d3c1ef3 100644 --- a/modules/gallery/libraries/MY_ORM.php +++ b/modules/gallery/libraries/MY_ORM.php @@ -32,7 +32,7 @@ class ORM extends ORM_Core { } public function save() { - model_cache::clear($this->object_name, $this->{$this->primary_key}, $this->primary_key); + model_cache::clear(); $result = parent::save(); $this->original = $this->object; return $result; diff --git a/modules/gallery/libraries/ORM_MPTT.php b/modules/gallery/libraries/ORM_MPTT.php index 46280d95..e371f159 100644 --- a/modules/gallery/libraries/ORM_MPTT.php +++ b/modules/gallery/libraries/ORM_MPTT.php @@ -285,6 +285,7 @@ class ORM_MPTT_Core extends ORM { // Lets reload to get the changes. $this->reload(); + $target->reload(); return $this; } diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 6512e9e5..05c4e656 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -140,6 +140,7 @@ class Item_Model extends ORM_MPTT { $original_parent = $this->parent(); parent::move_to($target, true); + model_cache::clear(); $this->relative_path_cache = null; rename($original_path, $this->file_path()); -- cgit v1.2.3 From e7c6861507ea7ca01d3d4ed7b4189c030c8d07b3 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 17 Jul 2009 16:58:00 -0700 Subject: Don't send back the gzipped version if we're using zlib.output_compression in PHP, since that means that the stream is already compressed. Fixes ticket 555. --- modules/gallery/controllers/combined.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/controllers/combined.php b/modules/gallery/controllers/combined.php index 925d052d..9a790fdf 100644 --- a/modules/gallery/controllers/combined.php +++ b/modules/gallery/controllers/combined.php @@ -60,14 +60,15 @@ class Combined_Controller extends Controller { $cache = Cache::instance(); $use_gzip = function_exists("gzencode") && - (strpos($input->server("HTTP_ACCEPT_ENCODING"), "gzip") !== false); + stripos($input->server("HTTP_ACCEPT_ENCODING"), "gzip") !== false && + (int) ini_get("zlib.output_compression") === 0; + if ($use_gzip && $content = $cache->get("{$key}_gz")) { header("Content-Encoding: gzip"); } else { // Fall back to non-gzipped if we have to $content = $cache->get($key); } - if (empty($content)) { Kohana::show_404(); } -- cgit v1.2.3 From 6200955003844ba9a196db72f068650f8056acda Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 17 Jul 2009 18:19:43 -0700 Subject: Don't bother making gzencoded version of combined CSS/JS if zlib.output_compression=On --- modules/gallery/libraries/Gallery_View.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/libraries/Gallery_View.php b/modules/gallery/libraries/Gallery_View.php index 133066d7..4b85f2f0 100644 --- a/modules/gallery/libraries/Gallery_View.php +++ b/modules/gallery/libraries/Gallery_View.php @@ -104,7 +104,10 @@ class Gallery_View_Core extends View { } $cache->set($key, $contents, array($type), 30 * 84600); - if (function_exists("gzencode")) { + + $use_gzip = function_exists("gzencode") && + (int) ini_get("zlib.output_compression") === 0; + if ($use_gzip) { $cache->set("{$key}_gz", gzencode($contents, 9, FORCE_GZIP), array($type, "gzip"), 30 * 84600); } -- cgit v1.2.3 From d692002bcfca1cc630ddd0e55b693744ef7fa924 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 17 Jul 2009 18:24:31 -0700 Subject: Don't show the combined CSS/JS elements if we didn't combine anything. Fixes ticket #554. --- modules/gallery/libraries/Gallery_View.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'modules') diff --git a/modules/gallery/libraries/Gallery_View.php b/modules/gallery/libraries/Gallery_View.php index 4b85f2f0..31231ca6 100644 --- a/modules/gallery/libraries/Gallery_View.php +++ b/modules/gallery/libraries/Gallery_View.php @@ -73,6 +73,10 @@ class Gallery_View_Core extends View { protected function combine_files($files, $type) { $links = array(); + if (empty($files)) { + return; + } + // Include the url in the cache key so that if the Gallery moves, we don't use old cached // entries. $key = array(url::abs_file("")); -- cgit v1.2.3 From df22832a5b7e7c1962940becab1c90aaec3392f9 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 17 Jul 2009 18:35:06 -0700 Subject: Rename "locale" helper to "locales" to avoid conflicting with PHP 5.3. Fixes ticket #194 --- modules/gallery/controllers/admin_languages.php | 6 +- modules/gallery/helpers/l10n_client.php | 2 +- modules/gallery/helpers/locale.php | 124 ------------------------ modules/gallery/helpers/locales.php | 124 ++++++++++++++++++++++++ modules/gallery/libraries/MY_View.php | 2 +- modules/gallery/views/l10n_client.html.php | 2 +- modules/user/helpers/user.php | 2 +- 7 files changed, 131 insertions(+), 131 deletions(-) delete mode 100644 modules/gallery/helpers/locale.php create mode 100644 modules/gallery/helpers/locales.php (limited to 'modules') diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php index d1b805da..ae90ad07 100644 --- a/modules/gallery/controllers/admin_languages.php +++ b/modules/gallery/controllers/admin_languages.php @@ -36,7 +36,7 @@ class Admin_Languages_Controller extends Admin_Controller { $form = $this->_languages_form(); if ($form->validate()) { module::set_var("gallery", "default_locale", $form->choose_language->locale->value); - locale::update_installed($form->choose_language->installed_locales->value); + locales::update_installed($form->choose_language->installed_locales->value); message::success(t("Settings saved")); } url::redirect("admin/languages"); @@ -89,8 +89,8 @@ class Admin_Languages_Controller extends Admin_Controller { } private function _languages_form() { - $all_locales = locale::available(); - $installed_locales = locale::installed(); + $all_locales = locales::available(); + $installed_locales = locales::installed(); $form = new Forge("admin/languages/save", "", "post", array("id" => "gLanguageSettingsForm")); $group = $form->group("choose_language") ->label(t("Language settings")); diff --git a/modules/gallery/helpers/l10n_client.php b/modules/gallery/helpers/l10n_client.php index 6d4da0eb..b576b4e1 100644 --- a/modules/gallery/helpers/l10n_client.php +++ b/modules/gallery/helpers/l10n_client.php @@ -74,7 +74,7 @@ class l10n_client_Core { $request->locales = array(); $request->messages = new stdClass(); - $locales = locale::installed(); + $locales = locales::installed(); foreach ($locales as $locale => $locale_data) { $request->locales[] = $locale; } diff --git a/modules/gallery/helpers/locale.php b/modules/gallery/helpers/locale.php deleted file mode 100644 index 41b78834..00000000 --- a/modules/gallery/helpers/locale.php +++ /dev/null @@ -1,124 +0,0 @@ -$code)) { - $installed[$code] = $available[$code]; - } - } - return $installed; - } - - static function update_installed($locales) { - // Ensure that the default is included... - $default = module::get_var("gallery", "default_locale"); - $locales = in_array($default, $locales) - ? $locales - : array_merge($locales, array($default)); - - module::set_var("gallery", "installed_locales", join("|", $locales)); - } - - // @todo Might want to add a localizable language name as well. - private static function _init_language_data() { - $l["af_ZA"] = "Afrikaans"; // Afrikaans - $l["ar_SA"] = "العربية"; // Arabic - $l["be_BY"] = "Беларускі"; // Belarusian - $l["bg_BG"] = "Български"; // Bulgarian - $l["ca_ES"] = "Catalan"; // Catalan - $l["cs_CZ"] = "Česky"; // Czech - $l["da_DK"] = "Dansk"; // Danish - $l["de_DE"] = "Deutsch"; // German - $l["el_GR"] = "Greek"; // Greek - $l["en_GB"] = "English (UK)"; // English (UK) - $l["en_US"] = "English (US)"; // English (US) - $l["es_AR"] = "Español (AR)"; // Spanish (AR) - $l["es_ES"] = "Español"; // Spanish (ES) - $l["es_MX"] = "Español (MX)"; // Spanish (MX) - $l["et_EE"] = "Eesti"; // Estonian - $l["eu_ES"] = "Euskara"; // Basque - $l["fa_IR"] = "فارسي"; // Farsi - $l["fi_FI"] = "Suomi"; // Finnish - $l["fr_FR"] = "Français"; // French - $l["ga_IE"] = "Gaeilge"; // Irish - $l["he_IL"] = "עברית"; // Hebrew - $l["hu_HU"] = "Magyar"; // Hungarian - $l["is_IS"] = "Icelandic"; // Icelandic - $l["it_IT"] = "Italiano"; // Italian - $l["ja_JP"] = "日本語"; // Japanese - $l["ko_KR"] = "한국말"; // Korean - $l["lt_LT"] = "Lietuvių"; // Lithuanian - $l["lv_LV"] = "Latviešu"; // Latvian - $l["nl_NL"] = "Nederlands"; // Dutch - $l["no_NO"] = "Norsk bokmål"; // Norwegian - $l["pl_PL"] = "Polski"; // Polish - $l["pt_BR"] = "Português Brasileiro"; // Portuguese (BR) - $l["pt_PT"] = "Português"; // Portuguese (PT) - $l["ro_RO"] = "Română"; // Romanian - $l["ru_RU"] = "Русский"; // Russian - $l["sk_SK"] = "Slovenčina"; // Slovak - $l["sl_SI"] = "Slovenščina"; // Slovenian - $l["sr_CS"] = "Srpski"; // Serbian - $l["sv_SE"] = "Svenska"; // Swedish - $l["tr_TR"] = "Türkçe"; // Turkish - $l["uk_UA"] = "Українська"; // Ukrainian - $l["vi_VN"] = "Tiếng Việt"; // Vietnamese - $l["zh_CN"] = "简体中文"; // Chinese (CN) - $l["zh_TW"] = "繁體中文"; // Chinese (TW) - asort($l, SORT_LOCALE_STRING); - self::$locales = $l; - } - - static function display_name($locale=null) { - if (empty(self::$locales)) { - self::_init_language_data(); - } - $locale or $locale = I18n::instance()->locale(); - - return self::$locales["$locale"]; - } - - static function is_rtl($locale=null) { - $locale or $locale = I18n::instance()->locale(); - list ($language, $territory) = explode('_', $locale . "_"); - return in_array($language, array("he", "fa", "ar")); - } -} \ No newline at end of file diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php new file mode 100644 index 00000000..3762b97b --- /dev/null +++ b/modules/gallery/helpers/locales.php @@ -0,0 +1,124 @@ +$code)) { + $installed[$code] = $available[$code]; + } + } + return $installed; + } + + static function update_installed($locales) { + // Ensure that the default is included... + $default = module::get_var("gallery", "default_locale"); + $locales = in_array($default, $locales) + ? $locales + : array_merge($locales, array($default)); + + module::set_var("gallery", "installed_locales", join("|", $locales)); + } + + // @todo Might want to add a localizable language name as well. + private static function _init_language_data() { + $l["af_ZA"] = "Afrikaans"; // Afrikaans + $l["ar_SA"] = "العربية"; // Arabic + $l["be_BY"] = "Беларускі"; // Belarusian + $l["bg_BG"] = "Български"; // Bulgarian + $l["ca_ES"] = "Catalan"; // Catalan + $l["cs_CZ"] = "Česky"; // Czech + $l["da_DK"] = "Dansk"; // Danish + $l["de_DE"] = "Deutsch"; // German + $l["el_GR"] = "Greek"; // Greek + $l["en_GB"] = "English (UK)"; // English (UK) + $l["en_US"] = "English (US)"; // English (US) + $l["es_AR"] = "Español (AR)"; // Spanish (AR) + $l["es_ES"] = "Español"; // Spanish (ES) + $l["es_MX"] = "Español (MX)"; // Spanish (MX) + $l["et_EE"] = "Eesti"; // Estonian + $l["eu_ES"] = "Euskara"; // Basque + $l["fa_IR"] = "فارسي"; // Farsi + $l["fi_FI"] = "Suomi"; // Finnish + $l["fr_FR"] = "Français"; // French + $l["ga_IE"] = "Gaeilge"; // Irish + $l["he_IL"] = "עברית"; // Hebrew + $l["hu_HU"] = "Magyar"; // Hungarian + $l["is_IS"] = "Icelandic"; // Icelandic + $l["it_IT"] = "Italiano"; // Italian + $l["ja_JP"] = "日本語"; // Japanese + $l["ko_KR"] = "한국말"; // Korean + $l["lt_LT"] = "Lietuvių"; // Lithuanian + $l["lv_LV"] = "Latviešu"; // Latvian + $l["nl_NL"] = "Nederlands"; // Dutch + $l["no_NO"] = "Norsk bokmål"; // Norwegian + $l["pl_PL"] = "Polski"; // Polish + $l["pt_BR"] = "Português Brasileiro"; // Portuguese (BR) + $l["pt_PT"] = "Português"; // Portuguese (PT) + $l["ro_RO"] = "Română"; // Romanian + $l["ru_RU"] = "Русский"; // Russian + $l["sk_SK"] = "Slovenčina"; // Slovak + $l["sl_SI"] = "Slovenščina"; // Slovenian + $l["sr_CS"] = "Srpski"; // Serbian + $l["sv_SE"] = "Svenska"; // Swedish + $l["tr_TR"] = "Türkçe"; // Turkish + $l["uk_UA"] = "Українська"; // Ukrainian + $l["vi_VN"] = "Tiếng Việt"; // Vietnamese + $l["zh_CN"] = "简体中文"; // Chinese (CN) + $l["zh_TW"] = "繁體中文"; // Chinese (TW) + asort($l, SORT_LOCALE_STRING); + self::$locales = $l; + } + + static function display_name($locale=null) { + if (empty(self::$locales)) { + self::_init_language_data(); + } + $locale or $locale = I18n::instance()->locale(); + + return self::$locales["$locale"]; + } + + static function is_rtl($locale=null) { + $locale or $locale = I18n::instance()->locale(); + list ($language, $territory) = explode('_', $locale . "_"); + return in_array($language, array("he", "fa", "ar")); + } +} \ No newline at end of file diff --git a/modules/gallery/libraries/MY_View.php b/modules/gallery/libraries/MY_View.php index 96dcc71b..84ee0892 100644 --- a/modules/gallery/libraries/MY_View.php +++ b/modules/gallery/libraries/MY_View.php @@ -45,7 +45,7 @@ class View extends View_Core { } public function body_attributes() { - if (locale::is_rtl()) { + if (locales::is_rtl()) { return 'class="rtl"'; } return ''; diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php index c0cbbfa2..c73719ca 100644 --- a/modules/gallery/views/l10n_client.html.php +++ b/modules/gallery/views/l10n_client.html.php @@ -9,7 +9,7 @@

locale::display_name())) ?>

+ array("language" => locales::display_name())) ?>
  • - +
  • -- cgit v1.2.3 From 050c82cf80b06a555252efaf701434b0cfd59bed Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 21 Jul 2009 11:09:23 -0700 Subject: Escape bare & symbols so that we use valid entities. Fixes ticket #577. --- modules/organize/views/organize.html.php | 2 +- modules/server_add/views/admin_server_add.html.php | 2 +- modules/server_add/views/server_add_tree_dialog.html.php | 2 +- modules/user/views/login.html.php | 2 +- themes/admin_default/views/admin.html.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'modules') diff --git a/modules/organize/views/organize.html.php b/modules/organize/views/organize.html.php index 65d67d04..1686d255 100644 --- a/modules/organize/views/organize.html.php +++ b/modules/organize/views/organize.html.php @@ -33,7 +33,7 @@ var CONFIRM_DELETE = "
    "> + ref="">
      diff --git a/modules/server_add/views/admin_server_add.html.php b/modules/server_add/views/admin_server_add.html.php index 588a9fca..30ab3536 100644 --- a/modules/server_add/views/admin_server_add.html.php +++ b/modules/server_add/views/admin_server_add.html.php @@ -11,7 +11,7 @@
        $path): ?>
      • - " + " id="icon_" class="gRemoveDir ui-icon ui-icon-trash"> X 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 21952849..a4eda3b9 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -1,7 +1,7 @@
      • - " + " id="gLogoutLink">
      • diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index 575f8a96..b0ddb6c5 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -45,7 +45,7 @@ admin_header_top() ?>
        • ')) ?>
        • - " + " id="gLogoutLink">
        • -- cgit v1.2.3 From 0546f0df13471664255a18b45c7464cc7f7f370e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 21 Jul 2009 13:39:40 -0700 Subject: Fix the bug that the quick menu fires for the wrong photo. This stems from using a single gQuickPane
          that we move around. A race condition happens when you mouse over two thumbnails quickly. Whichever server response loses the race gets displayed, and sometimes it's the one that you're no longer hovering over. Fix it by changing gQuickPane to be a class and creating a
          per thumbnail. Fixes ticket #290. --- modules/gallery/css/quick.css | 12 ++++++------ modules/gallery/js/quick.js | 20 ++++++++------------ modules/gallery/views/quick_pane.html.php | 2 +- themes/default/css/fix-ie.css | 4 ++-- 4 files changed, 17 insertions(+), 21 deletions(-) (limited to 'modules') diff --git a/modules/gallery/css/quick.css b/modules/gallery/css/quick.css index 0e45eac2..f153d475 100644 --- a/modules/gallery/css/quick.css +++ b/modules/gallery/css/quick.css @@ -1,4 +1,4 @@ -#gQuickPane { +.gQuickPane { position: absolute; top: 0; left: 0; @@ -17,7 +17,7 @@ padding: 0 !important; } -#gQuickPane { +.gQuickPane { background: #000; border-bottom: 1px solid #ccc; opacity: 0.9; @@ -26,19 +26,19 @@ left: 0; } -#gQuickPane a { +.gQuickPane a { cursor: pointer; float: left; margin: 4px; } -#gQuickPaneOptions { +.gQuickPaneOptions { background: #000; float: left; width: 100%; } -#gQuickPaneOptions li a { +.gQuickPaneOptions li a { display: block; float: none; width: auto; @@ -47,6 +47,6 @@ text-align: left; } -#gQuickPaneOptions li a:hover { +.gQuickPaneOptions li a:hover { background-color: #4d4d4d; } diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js index 3ac97f8e..fda6470f 100644 --- a/modules/gallery/js/quick.js +++ b/modules/gallery/js/quick.js @@ -12,15 +12,15 @@ var show_quick = function() { var cont = $(this); var quick = $(this).find(".gQuick"); var img = cont.find(".gThumbnail,.gResize"); - $("#gQuickPane").remove(); - cont.append("
          "); - $("#gQuickPane").hide(); - cont.hover(function() {}, hide_quick); + cont.find(".gQuickPane").remove(); + cont.append("
          "); + cont.find(".gQuickPane").hide(); + cont.hover(function() {}, function() { cont.find(".gQuickPane").remove(); }); $.get( quick.attr("href"), {}, function(data, textStatus) { - $("#gQuickPane").html(data).slideDown("fast"); + cont.find(".gQuickPane").html(data).slideDown("fast"); $(".ui-state-default").hover( function() { $(this).addClass("ui-state-hover"); @@ -29,13 +29,13 @@ var show_quick = function() { $(this).removeClass("ui-state-hover"); } ); - $("#gQuickPane a:not(.options)").click(function(e) { + cont.find(".gQuickPane a:not(.options)").click(function(e) { e.preventDefault(); quick_do(cont, $(this), img); }); - $("#gQuickPane a.options").click(function(e) { + cont.find(".gQuickPane a.options").click(function(e) { e.preventDefault(); - $("#gQuickPaneOptions").slideToggle("fast"); + cont.find(".gQuickPaneOptions").slideToggle("fast"); }); } ); @@ -76,7 +76,3 @@ var quick_do = function(cont, pane, img) { } return false; }; - -var hide_quick = function() { - $("#gQuickPane").remove(); -}; diff --git a/modules/gallery/views/quick_pane.html.php b/modules/gallery/views/quick_pane.html.php index eabf4a67..e5469696 100644 --- a/modules/gallery/views/quick_pane.html.php +++ b/modules/gallery/views/quick_pane.html.php @@ -15,7 +15,7 @@ -
          - + += 25): ?> + + \ No newline at end of file diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index d2cdd957..28b45be0 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,4 +1,20 @@ - $child): ?> - +
        • + "> + + +
          gBranchText"> + title) ?> +
          + +
          + +
            "> + +
          + +
        • -- cgit v1.2.3 From 52147cf6f857c4c54a2f3d753e72b27b5141d028 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 3 Aug 2009 21:45:54 -0700 Subject: Combine the quick menu and the thumb menu into a single menu called the "context" menu. This new context menu is generated using the typical event processing system, like our other menus. The specialized quick CSS and JS is now gone, replaced by our generic menu handling code. It's all rolled together currently using the thumb_menu UI for easy packaging. All the CSS and JS is updated. NOTE: the non-dialog links (rotate, album_cover) have a broken UI because they return JSON which the quick.js code handled specially, but we don't handle properly now. I need to fix this. --- modules/digibug/helpers/digibug_event.php | 4 +- modules/gallery/controllers/quick.php | 14 --- modules/gallery/css/quick.css | 52 ---------- modules/gallery/helpers/gallery.php | 102 ++++++++++++++++++++ modules/gallery/helpers/gallery_quick.php | 152 ------------------------------ modules/gallery/helpers/gallery_theme.php | 31 ------ modules/gallery/helpers/module.php | 8 +- modules/gallery/js/quick.js | 78 --------------- modules/gallery/libraries/Menu.php | 4 +- modules/gallery/libraries/Theme_View.php | 10 +- modules/gallery/views/quick_pane.html.php | 26 ----- themes/default/css/fix-ie.css | 4 - themes/default/css/screen.css | 9 +- themes/default/js/ui.init.js | 31 ++---- themes/default/views/album.html.php | 2 +- 15 files changed, 131 insertions(+), 396 deletions(-) delete mode 100644 modules/gallery/css/quick.css delete mode 100644 modules/gallery/helpers/gallery_quick.php delete mode 100644 modules/gallery/js/quick.js delete mode 100644 modules/gallery/views/quick_pane.html.php (limited to 'modules') diff --git a/modules/digibug/helpers/digibug_event.php b/modules/digibug/helpers/digibug_event.php index c4f9e560..efe66a0f 100644 --- a/modules/digibug/helpers/digibug_event.php +++ b/modules/digibug/helpers/digibug_event.php @@ -36,9 +36,9 @@ class digibug_event_Core { ->css_id("gDigibugLink")); } - static function thumb_menu($menu, $theme, $item) { + static function context_menu($menu, $theme, $item) { if ($item->type == "photo") { - $menu->get("options_menu") + $menu ->append( Menu::factory("link") ->id("digibug") diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index de027c1b..82176e02 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -18,20 +18,6 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Quick_Controller extends Controller { - public function pane($id) { - $item = model_cache::get("item", $id); - if (!access::can("view", $item) || !access::can("edit", $item)) { - return ""; - } - - $view = new View("quick_pane.html"); - $page_type = Input::instance()->get("page_type"); - $view->button_list = gallery_quick::get_quick_buttons($item, $page_type); - $view->item = $item; - $view->page_type = $page_type; - print $view; - } - public function rotate($id, $dir) { access::verify_csrf(); $item = model_cache::get("item", $id); diff --git a/modules/gallery/css/quick.css b/modules/gallery/css/quick.css deleted file mode 100644 index f153d475..00000000 --- a/modules/gallery/css/quick.css +++ /dev/null @@ -1,52 +0,0 @@ -.gQuickPane { - position: absolute; - top: 0; - left: 0; - text-align: center; - width: 100%; - height: auto; -} - -.gItem:hover { - background-color: #cfdeff; -} - -.gQuick { - border: none !important; - margin: 0 !important; - padding: 0 !important; -} - -.gQuickPane { - background: #000; - border-bottom: 1px solid #ccc; - opacity: 0.9; - position: absolute; - top: 0; - left: 0; -} - -.gQuickPane a { - cursor: pointer; - float: left; - margin: 4px; -} - -.gQuickPaneOptions { - background: #000; - float: left; - width: 100%; -} - -.gQuickPaneOptions li a { - display: block; - float: none; - width: auto; - margin: 0; - padding: .5em .5em .5em .8em; - text-align: left; -} - -.gQuickPaneOptions li a:hover { - background-color: #4d4d4d; -} diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 476e9cbe..085965a2 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -196,4 +196,106 @@ class gallery_Core { ->url(url::site("admin/maintenance"))); return $menu; } + + static function context_menu($menu, $theme, $item, $page_type) { + switch ($item->type) { + case "movie": + $edit_title = t("Edit this movie"); + $move_title = t("Move this movie to another album"); + $cover_title = t("Choose this movie as the album cover"); + $delete_title = t("Delete this movie"); + break; + + case "album": + $edit_title = t("Edit this album"); + $move_title = t("Move this album to another album"); + $cover_title = t("Choose this album as the album cover"); + $delete_title = t("Delete this album"); + break; + + default: + $edit_title = t("Edit this photo"); + $move_title = t("Move this photo to another album"); + $cover_title = t("Choose this photo as the album cover"); + $delete_title = t("Delete this photo"); + break; + } + + $csrf = access::csrf_token(); + $menu->append(Menu::factory("dialog") + ->id("edit") + ->label($edit_title) + ->css_clasS("ui-icon-pencil") + ->url(url::site("quick/form_edit/$item->id?page_type=$page_type"))); + + + if ($item->is_photo() && graphics::can("rotate")) { + $menu + ->append(Menu::factory("link") + ->id("rotate_ccw") + ->label(t("Rotate 90 degrees counter clockwise")) + ->css_class("ui-icon-rotate-ccw") + ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type"))) + ->append(Menu::factory("link") + ->id("rotate_cw") + ->label(t("Rotate 90 degrees clockwise")) + ->css_class("ui-icon-rotate-cw") + ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type"))); + } + + // Don't move photos from the photo page; we don't yet have a good way of redirecting after move + if ($page_type == "album") { + $menu + ->append(Menu::factory("dialog") + ->id("move") + ->label($move_title) + ->css_class("ui-icon-folder-open") + ->url(url::site("move/browse/$item->id"))); + } + + $parent = $item->parent(); + if (access::can("edit", $parent)) { + // We can't make this item the highlight if it's an album with no album cover, or if it's + // already the album cover. + if (($item->type == "album" && empty($item->album_cover_item_id)) || + ($item->type == "album" && $parent->album_cover_item_id == $item->album_cover_item_id) || + $parent->album_cover_item_id == $item->id) { + $disabledState = " ui-state-disabled"; + } else { + $disabledState = " "; + } + $menu + ->append(Menu::factory("link") + ->id("make_album_cover") + ->label($cover_title) + ->css_class($disabledState) + ->url( + url::site("quick/make_album_cover/$item->id?csrf=$csrf&page_type=$page_type"))) + ->append(Menu::factory("dialog") + ->id("delete") + ->label($delete_title) + ->css_class("ui-icon-trash") + ->css_id("gQuickDelete") + ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&page_type=$page_type"))); + } + + if ($item->is_album()) { + $menu + ->append(Menu::factory("dialog") + ->id("add_item") + ->label(t("Add a photo")) + ->css_class("add_item") + ->url(url::site("simple_uploader/app/$item->id"))) + ->append(Menu::factory("dialog") + ->id("add_album") + ->label(t("Add an album")) + ->css_class("add_album") + ->url(url::site("form/add/albums/$item->id?type=album"))) + ->append(Menu::factory("dialog") + ->id("edit_permissions") + ->label(t("Edit permissions")) + ->css_class("permissions") + ->url(url::site("permissions/browse/$item->id"))); + } + } } \ No newline at end of file diff --git a/modules/gallery/helpers/gallery_quick.php b/modules/gallery/helpers/gallery_quick.php deleted file mode 100644 index 8a92890b..00000000 --- a/modules/gallery/helpers/gallery_quick.php +++ /dev/null @@ -1,152 +0,0 @@ -name == "gallery") { - continue; - } - $class_name = "{$module->name}_quick"; - if (method_exists($class_name, "buttons")) { - $module_buttons = call_user_func(array($class_name, "buttons"), $item, $page_type); - foreach (array("left", "center", "right", "additional") as $position) { - if (!empty($module_buttons[$position])) { - $buttons[$position] = array_merge($buttons[$position], $module_buttons[$position]); - } - } - } - } - - $sorted_buttons->main = array(); - foreach (array("left", "center", "right") as $position) { - $sorted_buttons->main = array_merge($sorted_buttons->main, $buttons[$position]); - } - - $sorted_buttons->additional = $buttons["additional"]; - $max_display = empty($sorted_buttons->additional) ? 6 : 5; - if (count($sorted_buttons->main) >= $max_display) { - $to_move = array_slice($sorted_buttons->main, 5); - $sorted_buttons->additional = array_merge($to_move, $sorted_buttons->additional); - for ($i = count($sorted_buttons->main); $i >= 5; $i--) { - unset($sorted_buttons->main[$i]); - } - } - - return $sorted_buttons; - } - - static function buttons($item, $page_type) { - $elements = array("left" => array(), "center" => array(), "right" => array(), - "additional" => array()); - switch ($item->type) { - case "movie": - $edit_title = t("Edit this movie"); - $move_title = t("Move this movie to another album"); - $cover_title = t("Choose this movie as the album cover"); - $delete_title = t("Delete this movie"); - break; - case "album": - $edit_title = t("Edit this album"); - $move_title = t("Move this album to another album"); - $cover_title = t("Choose this album as the album cover"); - $delete_title = t("Delete this album"); - break; - default: - $edit_title = t("Edit this photo"); - $move_title = t("Move this photo to another album"); - $cover_title = t("Choose this photo as the album cover"); - $delete_title = t("Delete this photo"); - break; - } - - $csrf = access::csrf_token(); - $elements["left"][] = (object)array( - "title" => $edit_title, - "class" => "gDialogLink gButtonLink", - "icon" => "ui-icon-pencil", - "href" => url::site("quick/form_edit/$item->id?page_type=$page_type")); - - if ($item->is_photo() && graphics::can("rotate")) { - $elements["left"][] = - (object)array( - "title" => t("Rotate 90 degrees counter clockwise"), - "class" => "gButtonLink", - "icon" => "ui-icon-rotate-ccw", - "href" => url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type")); - $elements["left"][] = - (object)array( - "title" => t("Rotate 90 degrees clockwise"), - "class" => "gButtonLink", - "icon" => "ui-icon-rotate-cw", - "href" => url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type")); - } - - // Don't move photos from the photo page; we don't yet have a good way of redirecting after move - if ($page_type == "album") { - $elements["left"][] = (object)array( - "title" => $move_title, - "class" => "gDialogLink gButtonLink", - "icon" => "ui-icon-folder-open", - "href" => url::site("move/browse/$item->id")); - } - - $parent = $item->parent(); - if (access::can("edit", $parent)) { - // We can't make this item the highlight if it's an album with no album cover, or if it's - // already the album cover. - if (($item->type == "album" && empty($item->album_cover_item_id)) || - ($item->type == "album" && $parent->album_cover_item_id == $item->album_cover_item_id) || - $parent->album_cover_item_id == $item->id) { - $disabledState = " ui-state-disabled"; - } else { - $disabledState = " "; - } - $elements["right"][] = (object)array( - "title" => $cover_title, - "class" => "gButtonLink$disabledState", - "icon" => "ui-icon-star", - "href" => url::site("quick/make_album_cover/$item->id?csrf=$csrf&page_type=$page_type")); - - $elements["right"][] = (object)array( - "title" => $delete_title, - "class" => "gDialogLink gButtonLink", - "icon" => "ui-icon-trash", - "id" => "gQuickDelete", - "href" => url::site("quick/form_delete/$item->id?csrf=$csrf&page_type=$page_type")); - } - - if ($item->is_album()) { - $elements["additional"][] = (object)array( - "title" => t("Add a photo"), - "class" => "add_item gDialogLink", - "href" => url::site("simple_uploader/app/$item->id")); - $elements["additional"][] = (object)array( - "title" => t("Add an album"), - "class" => "add_album gDialogLink", - "href" => url::site("form/add/albums/$item->id?type=album")); - $elements["additional"][] = (object)array( - "title" => t("Edit permissions"), - "class" => "permissions gDialogLink", - "href" => url::site("permissions/browse/$item->id")); - } - return $elements; - } -} diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php index d3751b80..8fe1c768 100644 --- a/modules/gallery/helpers/gallery_theme.php +++ b/modules/gallery/helpers/gallery_theme.php @@ -24,11 +24,6 @@ class gallery_theme_Core { if ($session->get("debug")) { $theme->css("debug.css"); } - if (($theme->page_type == "album" || $theme->page_type == "photo") - && access::can("edit", $theme->item())) { - $theme->css("quick.css"); - $theme->script("quick.js"); - } if (module::is_active("rss")) { if ($item = $theme->item()) { @@ -51,32 +46,6 @@ class gallery_theme_Core { return $buf; } - static function resize_top($theme, $item) { - if (access::can("edit", $item)) { - $edit_link = url::site("quick/pane/$item->id?page_type=photo"); - return "
          "; - } - } - - static function resize_bottom($theme, $item) { - if (access::can("edit", $item)) { - return "
          "; - } - } - - static function thumb_top($theme, $child) { - if (access::can("edit", $child)) { - $edit_link = url::site("quick/pane/$child->id?page_type=album"); - return "
          "; - } - } - - static function thumb_bottom($theme, $child) { - if (access::can("edit", $child)) { - return "
          "; - } - } - static function admin_head($theme) { $session = Session::instance(); if ($session->get("debug")) { diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index 0d483206..03d538a9 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -274,11 +274,9 @@ class module_Core { array_shift($args); $function = str_replace(".", "_", $name); - foreach (self::$modules as $module) { - if (!$module->active) { - continue; - } - + // @todo: consider calling gallery_event first, since for things menus we need it to do some + // setup + foreach (self::$active as $module) { $class = "{$module->name}_event"; if (method_exists($class, $function)) { call_user_func_array(array($class, $function), $args); diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js deleted file mode 100644 index fda6470f..00000000 --- a/modules/gallery/js/quick.js +++ /dev/null @@ -1,78 +0,0 @@ -$(document).ready(function() { - if ($("#gAlbumGrid").length) { - // @todo Add quick edit pane for album (meta, move, permissions, delete) - $(".gItem").hover(show_quick, function() {}); - } - if ($("#gPhoto").length) { - $("#gPhoto").hover(show_quick, function() {}); - } -}); - -var show_quick = function() { - var cont = $(this); - var quick = $(this).find(".gQuick"); - var img = cont.find(".gThumbnail,.gResize"); - cont.find(".gQuickPane").remove(); - cont.append("
          "); - cont.find(".gQuickPane").hide(); - cont.hover(function() {}, function() { cont.find(".gQuickPane").remove(); }); - $.get( - quick.attr("href"), - {}, - function(data, textStatus) { - cont.find(".gQuickPane").html(data).slideDown("fast"); - $(".ui-state-default").hover( - function() { - $(this).addClass("ui-state-hover"); - }, - function() { - $(this).removeClass("ui-state-hover"); - } - ); - cont.find(".gQuickPane a:not(.options)").click(function(e) { - e.preventDefault(); - quick_do(cont, $(this), img); - }); - cont.find(".gQuickPane a.options").click(function(e) { - e.preventDefault(); - cont.find(".gQuickPaneOptions").slideToggle("fast"); - }); - } - ); -}; - -var quick_do = function(cont, pane, img) { - if (pane.hasClass("ui-state-disabled")) { - return false; - } - if (pane.hasClass("gDialogLink")) { - openDialog(pane); - } else { - img.css("opacity", "0.1"); - cont.addClass("gLoadingLarge"); - $.ajax({ - type: "GET", - url: pane.attr("href"), - dataType: "json", - success: function(data) { - img.css("opacity", "1"); - cont.removeClass("gLoadingLarge"); - if (data.src) { - img.attr("width", data.width); - img.attr("height", data.height); - img.attr("src", data.src); - if (data.height > data.width) { - img.css("margin-top", -32); - } else { - img.css("margin-top", 0); - } - } else if (data.location) { - window.location = data.location; - } else if (data.reload) { - window.location.reload(); - } - } - }); - } - return false; -}; diff --git a/modules/gallery/libraries/Menu.php b/modules/gallery/libraries/Menu.php index a39b59a5..263dc38d 100644 --- a/modules/gallery/libraries/Menu.php +++ b/modules/gallery/libraries/Menu.php @@ -91,7 +91,7 @@ class Menu_Element_Link extends Menu_Element { } else { $css_class = ""; } - return "
        • url\" " . + return "
        • url\" " . "title=\"$this->label\">$this->label
        • "; } } @@ -111,7 +111,7 @@ class Menu_Element_Dialog extends Menu_Element { } else { $css_class = ""; } - return "
        • url\" " . + return "
        • url\" " . "title=\"$this->label\">$this->label
        • "; } } diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php index 360e5e46..24dea729 100644 --- a/modules/gallery/libraries/Theme_View.php +++ b/modules/gallery/libraries/Theme_View.php @@ -111,14 +111,16 @@ class Theme_View_Core extends Gallery_View { return $menu->compact(); } - public function thumb_menu($item) { + public function context_menu($item) { $menu = Menu::factory("root") ->append(Menu::factory("submenu") - ->id("options_menu") + ->id("context_menu") ->label(t("Options"))) - ->css_class("gThumbMenu"); + ->css_class("gContextMenu"); - module::event("thumb_menu", $menu, $this, $item); + $page_type = Input::instance()->get("page_type"); + gallery::context_menu($menu, $this, $item, $page_type); + module::event("context_menu", $menu, $this, $item, $page_type); return $menu->compact(); } diff --git a/modules/gallery/views/quick_pane.html.php b/modules/gallery/views/quick_pane.html.php deleted file mode 100644 index e5469696..00000000 --- a/modules/gallery/views/quick_pane.html.php +++ /dev/null @@ -1,26 +0,0 @@ - -main as $button): ?> - - - title ?> - - - - -additional)): ?> -"> - - - - - - - diff --git a/themes/default/css/fix-ie.css b/themes/default/css/fix-ie.css index c7c1ebad..eee88c15 100644 --- a/themes/default/css/fix-ie.css +++ b/themes/default/css/fix-ie.css @@ -35,7 +35,3 @@ input.submit { .gPager .ui-icon-right { width: 60px; } - -.gQuickPane { - height: 32px !important; -} \ No newline at end of file diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index c5a9956d..eb092b83 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -588,24 +588,25 @@ form .gError, /* Thumb Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#gContent .gThumbMenu { +#gContent .gContextMenu { bottom: 0; left: 0; position: absolute; width: 100%; + display: none; } -#gContent .gThumbMenu li { +#gContent .gContextMenu li { border-left: none; border-right: none; border-bottom: none; } -#gContent .gThumbMenu li li { +#gContent .gContextMenu li li { padding: .3em; } -#gContent .gThumbMenu a:hover { +#gContent .gContextMenu a:hover { text-decoration: none; } diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 11cd06ed..d796cb67 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -32,7 +32,6 @@ $(document).ready(function() { $("#gMessage li").showMessage(); // Initialize dialogs - $(".gMenuLink").addClass("gDialogLink"); $("#gLoginLink").addClass("gDialogLink"); var dialogLinks = $(".gDialogLink"); for (var i=0; i < dialogLinks.length; i++) { @@ -57,9 +56,6 @@ $(document).ready(function() { if ($("#gAlbumGrid").length) { // Vertical align thumbnails/metadata in album grid $(".gItem").vAlign(); - $(".gQuick").ajaxStop(function(){ - $(".gItem").vAlign(); - }); } // Photo/Item item view only @@ -97,26 +93,19 @@ $(document).ready(function() { } ); - // Initialize thumbnail menus - // @todo Toggle between north and south caret's on hover - if ($("#gContent .gThumbMenu").length) { - $("#gContent .gThumbMenu li").addClass("ui-state-default"); - $("#gContent .gThumbMenu li a") - .not('[class]') - .addClass("gButtonLink ui-icon ui-icon-caret-l-n") - .css({ - height: "10px", - margin: "0", - padding: "0 0 3px 0" - }); - - $(".gThumbMenu ul").hide(); - $(".gThumbMenu").hover( + // Initialize context menus + if ($("#gContent .gContextMenu").length) { + $("#gContent .gContextMenu li").addClass("ui-state-default"); + $(".gContextMenu").parent().hover( function() { - $(this).find("ul").slideDown("fast"); + $(this).find(".gContextMenu").slideDown("fast"); + var dialogLinks = $(this).find(".gDialogLink"); + for (var i = 0; i < dialogLinks.length; i++) { + $(dialogLinks[i]).bind("click", handleDialogEvent); + } }, function() { - $(this).find("ul").slideUp("slow"); + $(this).find(".gContextMenu").slideUp("slow"); } ); } diff --git a/themes/default/views/album.html.php b/themes/default/views/album.html.php index 65ea3381..ce57458e 100644 --- a/themes/default/views/album.html.php +++ b/themes/default/views/album.html.php @@ -19,7 +19,7 @@ thumb_img(array("class" => "gThumbnail")) ?> thumb_bottom($child) ?> - thumb_menu($child) ?> + context_menu($child) ?>

          title) ?>

          "> + ref="">
          -- cgit v1.2.3 From e8a3fe97a43dc257a70431defbcc6fb330cdfee2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 09:09:33 -0700 Subject: Fix whitespace. --- modules/organize/views/organize_dialog.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 89182347..3acee05c 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -14,7 +14,7 @@
          -
          +
            -- cgit v1.2.3 From 83e850bc332ce6c13f9b0b7a396f2fe8d9260eb6 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 09:19:20 -0700 Subject: Minor style fixes. --- modules/organize/js/organize.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'modules') diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 0f8f7fa1..ec6bd924 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -8,16 +8,19 @@ helper: function(event, ui) { var selected = $(".ui-draggable.ui-state-selected img"); if (selected.length) { - var set = $('
            ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), - offset = $(this).offset(), - click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; + var set = $('
            ') + .css({ + zIndex: 2000, + width: 80, + height: Math.ceil(selected.length / 5) * 16 + }); + var offset = $(this).offset(); + var click = {left: event.pageX - offset.left, top: event.pageY - offset.top}; selected.each(function(i) { var row = parseInt(i / 5); var j = i - (row * 5); - var o = $(this).offset(); - var copy = $(this).clone() .css({ width: $(this).width(), height: $(this).height(), display: "block", @@ -25,7 +28,7 @@ left: o.left - event.pageX, top: o.top - event.pageY }) .appendTo(set) - .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); + .animate({ width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20) }, 500); }); return set; } @@ -35,6 +38,7 @@ start: function(event, ui) { $("#gMicroThumbPanel .ui-state-selected").hide(); }, + drag: function(event, ui) { var top = $("#gMicroThumbPanel").offset().top; var height = $("#gMicroThumbPanel").height(); @@ -52,8 +56,9 @@ greedy: true, drop: function(event, ui) { $.organize.do_drop({ - url: rearrange_url.replace("__TARGET_ID__", $(".currentDropTarget").attr("ref")) - .replace("__BEFORE__", $(".currentDropTarget").css("borderLeftStyle") == "solid" ? "before" : "after"), + url: rearrange_url + .replace("__TARGET_ID__", $(".currentDropTarget").attr("ref")) + .replace("__BEFORE__", $(".currentDropTarget").css("borderLeftStyle") == "solid" ? "before" : "after"), source: $(ui.helper).children("img") }); } @@ -86,8 +91,9 @@ if (source_ids.length) { $("#gOrganize .gProgressBar").progressbar().progressbar("value", 0); $("#gOrganizeProgress").animate( - {height: "toggle", display: "toggle"}, - {duration: "fast", + { height: "toggle", display: "toggle" }, + { + duration: "fast", step: function() { }, complete: function() { -- cgit v1.2.3 From 98361e76134fd7ed5df40f2bcde30fd7f5d51708 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 09:25:29 -0700 Subject: Add a @todo to defer loading the script/css to the organize dialog. --- modules/organize/helpers/organize_theme.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'modules') diff --git a/modules/organize/helpers/organize_theme.php b/modules/organize/helpers/organize_theme.php index de812261..61b6fe7d 100644 --- a/modules/organize/helpers/organize_theme.php +++ b/modules/organize/helpers/organize_theme.php @@ -21,6 +21,10 @@ class organize_theme { static function head($theme) { $item = $theme->item(); if ($item && access::can("edit", $item) && $item->is_album()) { + // @todo: Defer loading js/css until we're loading the organize dialog as

            diff --git a/themes/admin_default/css/admin_screen.css b/themes/admin_default/css/admin_screen.css index d408acf0..913631dc 100644 --- a/themes/admin_default/css/admin_screen.css +++ b/themes/admin_default/css/admin_screen.css @@ -451,8 +451,20 @@ li.gDefaultGroup h4, li.gDefaultGroup .gUser { cursor: pointer; } -#gLanguageSettingsForm .checklist li { - width: 150px; - overflow: hidden; +#gLanguagesForm table { + width: 400px; + float: left; + margin: 0 3em 1em 0; +} +#gLanguagesForm .installed { + background-color: #EEEEEE; } +#gLanguagesForm .default { + background-color: #C5DBEC; + font-weight: bold; +} +#gLanguagesForm input, #gShareTranslationsForm, #gLanguages h2 { + clear: both; +} + -- cgit v1.2.3 From 1d5262f9c354a8564f05a8a31b915ad479f4d361 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 28 Aug 2009 13:44:01 -0700 Subject: Fix ticket #591: reCaptcha always on the page. 1) move creating the "Add a comment" button into the comments.html.php 2) use $.get() to retrieve the comment add form --- modules/comment/helpers/comment_theme.php | 2 -- modules/comment/js/comment.js | 10 +++++++++- modules/comment/views/comments.html.php | 10 ++++++++-- themes/default/css/screen.css | 7 +++++++ themes/default/js/ui.init.js | 12 ------------ themes/default/views/movie.html.php | 3 --- themes/default/views/photo.html.php | 3 --- 7 files changed, 24 insertions(+), 23 deletions(-) (limited to 'modules') diff --git a/modules/comment/helpers/comment_theme.php b/modules/comment/helpers/comment_theme.php index b807e2cf..38a00b5c 100644 --- a/modules/comment/helpers/comment_theme.php +++ b/modules/comment/helpers/comment_theme.php @@ -26,7 +26,6 @@ class comment_theme_Core { static function photo_bottom($theme) { $block = new Block; $block->css_id = "gComments"; - $block->anchor = t("comments"); $block->title = t("Comments"); $view = new View("comments.html"); @@ -37,7 +36,6 @@ class comment_theme_Core { ->find_all(); $block->content = $view; - $block->content .= comment::get_add_form($theme->item())->render("form.html"); return $block; } } \ No newline at end of file diff --git a/modules/comment/js/comment.js b/modules/comment/js/comment.js index 00fc6027..9fd63c1a 100644 --- a/modules/comment/js/comment.js +++ b/modules/comment/js/comment.js @@ -1,5 +1,13 @@ $("document").ready(function() { - ajaxify_comment_form(); + $("#gAddCommentButton").click(function(event) { + event.preventDefault(); + $.get($(this).attr("href"), + {}, + function(data) { + $("#gCommentDetail").append(data); + ajaxify_comment_form(); + }); + }); }); function ajaxify_comment_form() { diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index f7251389..6dce9971 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -1,11 +1,17 @@ + id})") ?>" id="gAddCommentButton" + class="gButtonLink ui-corner-all ui-icon-left ui-state-default right"> + + + +
            count()): ?>

            comment!", array("attrs" => "href=\"#add_comment_form\" class=\"showCommentForm\"")) ?>

            -
              +
              • @@ -26,4 +32,4 @@

              - +
            diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index ecae2bb2..481581a2 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -530,6 +530,7 @@ form .gError, #gContent #gComments { margin-top: 2em; + position: relative; } #gContent #gComments ul li { @@ -561,6 +562,12 @@ form .gError, width: 32px; } +#gAddCommentButton { + position: absolute; + right: 0; + top: 2px; +} + #gContent #gAddCommentForm { margin-top: 2em; } diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 2391f638..67cdb968 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -110,18 +110,6 @@ $(document).ready(function() { $(this).gallery_context_menu(); }); - // Collapse comments form, insert button to expand - if ($("#gAddCommentForm").length) { - var showCommentForm = '' - + '' + ADD_A_COMMENT + ''; - $("#gAddCommentForm").hide(); - $("#gComments").prepend(showCommentForm); - $(".showCommentForm").click(function(){ - $("#gAddCommentForm").show(1000); - }); - } - // Add scroll effect for links to named anchors $.localScroll({ queue: true, diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index c8ecd769..29789f8e 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -32,9 +32,6 @@
            description)) ?>
          - photo_bottom() ?> context_menu($item, "#gMovieId-{$item->id}") ?>
          diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index fa5def47..39e61ef6 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -55,8 +55,5 @@
          description)) ?>
          - photo_bottom() ?>
      -- cgit v1.2.3 From cb2171d0825251d619b53f6f80d217326fb6bab5 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 14:27:37 -0700 Subject: Display the sort order in the Organize dialog, and allow users to change the sort order on the fly. --- modules/gallery/helpers/album.php | 21 ++++++--- modules/organize/controllers/organize.php | 21 ++++++++- modules/organize/css/organize.css | 59 ++++--------------------- modules/organize/js/organize.js | 22 +++++++-- modules/organize/views/organize_dialog.html.php | 20 ++++----- 5 files changed, 71 insertions(+), 72 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index 1b6b875d..d46f21ac 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -116,13 +116,7 @@ class album_Core { $sort_order->dropdown("column", array("id" => "gAlbumSortColumn")) ->label(t("Sort by")) - ->options(array("weight" => t("Manual"), - "captured" => t("Date captured"), - "created" => t("Date uploaded"), - "title" => t("Title"), - "updated" => t("Date modified"), - "view_count" => t("Number of views"), - "rand_key" => t("Random"))) + ->options(album::get_sort_order_options()) ->selected($parent->sort_column); $sort_order->dropdown("direction", array("id" => "gAlbumSortDirection")) ->label(t("Order")) @@ -137,4 +131,17 @@ class album_Core { $form->add_rules_from(ORM::factory("item")); return $form; } + + /** + * Return a structured set of all the possible sort orders. + */ + static function get_sort_order_options() { + return array("weight" => t("Manual"), + "captured" => t("Date captured"), + "created" => t("Date uploaded"), + "title" => t("Title"), + "updated" => t("Date modified"), + "view_count" => t("Number of views"), + "rand_key" => t("Random")); + } } diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index f56ad006..10b109f6 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -25,7 +25,7 @@ class Organize_Controller extends Controller { access::required("edit", $item); $v = new View("organize_dialog.html"); - $v->title = $item->title; + $v->album = $item; $parents = array(); foreach ($item->parents() as $parent) { $parents[$parent->id] = 1; @@ -84,6 +84,25 @@ class Organize_Controller extends Controller { "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token()))); } + function resort($target_id, $col, $dir) { + access::verify_csrf(); + + $album = ORM::factory("item", $target_id); + access::required("view", $album); + access::required("edit", $album); + + $options = album::get_sort_order_options(); + if (!isset($options[$col])) { + return; + } + + $album->sort_column = $col; + $album->sort_order = $dir; + $album->save(); + + print self::_get_micro_thumb_grid($album, 0); + } + private static function _get_micro_thumb_grid($item, $offset) { $v = new View("organize_thumb_grid.html"); $v->item = $item; diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index d717bcae..52de87fc 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -134,63 +134,20 @@ } /**************************************************************** - * Organize Edit Drawer styling + * Organize Controls styling */ -#gOrganizeEditDrawer { +#gOrganizeControls { + padding-left: 8px; background-color: #13A; + color: #ccc; width: 100% !important; } -#gOrganizeEditDrawerPanel { - background-color: #fff; - border: 1px solid #13A; - display: none; - height: 195px; -} - -#gOrganizeEditDrawerHandle { - height: 30px; -} - -#gOrganizeEditHandleLeft { - background-color: #FFF; - float: left; - height: 30px; - width: 15px; -} - -#gOrganizeEditHandleButtonsMiddle, -#gOrganizeEditHandleButtonsLeft { - float: left; - height: 20px; - padding: 2px 10px; -} - -#gOrganizeEditHandleButtonsMiddle { - margin-left: 20px; -} - -#gOrganizeEditHandleButtonsMiddle a, -#gOrganizeEditHandleButtonsLeft a { - float: left; - margin: 0 2.5px; -} - -#gOrganizeEditHandleButtonsRight { - float: right; - height: 20px; - padding: 2px 10px; -} - -#gOrganizeEditHandleButtonsRight a { - float: left; - margin: 0 2.5px; +#gOrganizeControls select { + display: inline; } -#gOrganizeEditHandleRight { - background-color: #FFF; - background-position: -15px 0; +#gOrganizeClose { float: right; - height: 30px; - width: 15px; + margin-right: 12px; } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index ec6bd924..96309787 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -125,9 +125,8 @@ $("#gOrganize .gProgressBar").progressbar("value", data.percent_complete); if (data.done) { var height = $("#gOrganizeProgress").height(); - $("#gOrganizeProgress").toggle(); + $("#gOrganizeProgress").slideUp(); $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); - //$("#gMicroThumbPanel").height($("#gMicroThumbPanel").height() + height); if (data.tree) { $("#gOrganizeAlbumTree").html(data.tree); } @@ -171,10 +170,14 @@ window.location.reload(); }); - $("#gDialog #gMicroThumbDone").click(function(event) { + $("#gDialog #gOrganizeClose").click(function(event) { $("#gDialog").dialog("close"); }); + $("#gOrganizeSortColumn,#gOrganizeSortDir").change(function(event) { + $.organize.resort($("#gOrganizeSortColumn").attr("value"), $("#gOrganizeSortDir").attr("value")); + }); + $.organize.set_handlers(); }, @@ -219,6 +222,19 @@ $("#gMicroThumbGrid").html(data); $.organize.set_handlers(); }); + }, + + /** + * Change the sort order. + */ + resort: function(column, dir) { + var url = sort_order_url + .replace("__COL__", column) + .replace("__DIR__", dir); + $.get(url, function(data) { + $("#gMicroThumbGrid").html(data); + $.organize.set_handlers(); + }); } }; })(jQuery); diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 7c09266f..a3aae05b 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -2,9 +2,10 @@
      -

      p::purify($title))) ?>

      +

      p::purify($album->title))) ?>

      @@ -27,15 +28,14 @@
      -
      -
      -
      -
      -
      - -
      -
      +
      + +
      + + "gOrganizeSortColumn"), album::get_sort_order_options(), $album->sort_column) ?> + "gOrganizeSortDir"), array("ASC" => "Ascending", "DESC" => "Descending"), $album->sort_order) ?> +
      diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index 5adb487a..31dc9af5 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -1,5 +1,5 @@ -children(25, $offset) as $child): ?> +children(25, $offset) as $child): ?>
    • "> @@ -8,10 +8,10 @@
    • -children_count() > $offset): ?> +children_count() > $offset): ?> + * + * @return the string escaped for use in JavaScript. + */ + function for_js() { + return self::_escape_for_js($this->_raw_string); + } + + /** + * Safe for use HTML (purified HTML) + * + * Example:
      +   *   
      purified_html() ?> + *
      + * @return the string escaped for use in HTML. + */ + function purified_html() { + if ($this->_is_safe_html) { + return $this; + } else { + return SafeString::of(self::_purify_for_html($this->_raw_string), true); + } + } + + /** + * 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..cdae3e99 --- /dev/null +++ b/modules/gallery/tests/SafeString_Test.php @@ -0,0 +1,111 @@ +world

      "); + $this->assert_true($safe_string instanceof SafeString); + $this->assert_equal("hello

      world

      ", + $safe_string->unescaped()); + } + + public function toString_escapes_for_html_test() { + $safe_string = new SafeString("hello

      world

      "); + $this->assert_equal("hello <p>world</p>", + $safe_string); + } + + public function toString_for_safe_string_test() { + $safe_string = new SafeString("hello

      world

      "); + $safe_string->mark_html_safe(); + $this->assert_equal("hello

      world

      ", + $safe_string); + } + + public function for_html_test() { + $safe_string = new SafeString("hello

      world

      "); + $this->assert_equal("hello <p>world</p>", + $safe_string->for_html()); + } + + public function safestring_of_safestring_test() { + $safe_string = new SafeString("hello

      world

      "); + $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

      world

      ", $raw_string); + $this->assert_equal("hello <p>world</p>", $safe_string_2); + } + + public function for_js_test() { + $safe_string = new SafeString('"Foo\'s bar"'); + $js_string = $safe_string->for_js(); + $this->assert_equal('\\"Foo<\\/em>\\\'s bar\\"', + $js_string); + } + + public function string_safestring_equality_test() { + $safe_string = new SafeString("hello

      world

      "); + $this->assert_equal("hello

      world

      ", + $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

      world

      "); + $this->assert_equal("hello

      world

      ", $safe_string->unescaped()); + } + + public function of_safe_html_test() { + $safe_string = SafeString::of("hello

      world

      ")->mark_html_safe(); + $this->assert_equal("hello

      world

      ", $safe_string->for_html()); + } + + 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("hello's

      world

      ")->mark_html_safe(); + $safe_string_2 = new SafeString($safe_string); + $this->assert_equal("hello's

      world

      ", $safe_string_2); + $this->assert_equal("hello\\'s

      world<\\/p>", $safe_string_2->for_js()); + } + + public function safestring_of_safestring_preserves_html_safe_status_test() { + $safe_string = SafeString::of("hello's

      world

      ") + ->mark_html_safe(); + $safe_string_2 = new SafeString($safe_string); + $this->assert_equal("hello's

      world

      ", $safe_string_2); + $this->assert_equal("hello\\'s

      world<\\/p>", $safe_string_2->for_js()); + } + + public function safestring_of_safestring_safe_status_override_test() { + $safe_string = new SafeString("hello

      world

      "); + $safe_string_2 = SafeString::of($safe_string)->mark_html_safe(); + $this->assert_equal("hello

      world

      ", $safe_string_2); + } +} diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 9bde11dc..1d52237c 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -19,87 +19,278 @@ */ 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", "", $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 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 "expr_append($inline_html); + } + + // Note: This approach won't catch }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('{]*>}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, "of"), $tokens, $token_number + 2) && + self::_token_matches("(", $tokens, $token_number + 3)) { + $frame->is_safestring(true); + $frame->expr_append("::of("); + + $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 ($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 ? >: + * JS_XSS: + * In + * + * @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) * diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index cdae3e99..73d82c34 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -18,13 +18,6 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class SafeString_Test extends Unit_Test_Case { - public function p_clean_returns_safestring_instance_test() { - $safe_string = p::clean("hello

      world

      "); - $this->assert_true($safe_string instanceof SafeString); - $this->assert_equal("hello

      world

      ", - $safe_string->unescaped()); - } - public function toString_escapes_for_html_test() { $safe_string = new SafeString("hello

      world

      "); $this->assert_equal("hello <p>world</p>", @@ -61,6 +54,20 @@ class SafeString_Test extends Unit_Test_Case { $js_string); } + public function for_html_attr_test() { + $safe_string = new SafeString('"Foo\'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('"Foo\'s bar"')->mark_html_safe(); + $attr_string = $safe_string->for_html_attr(); + $this->assert_equal('"Foo's bar"', + $attr_string); + } + public function string_safestring_equality_test() { $safe_string = new SafeString("hello

      world

      "); $this->assert_equal("hello

      world

      ", -- cgit v1.2.3 From 0d16cc1c106dc324fde59cac54fa82e4a70e04e2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 12:12:53 -0700 Subject: Clean up the test and get it working. --- modules/gallery/tests/Item_Helper_Test.php | 69 ++++++++---------------------- 1 file changed, 17 insertions(+), 52 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/Item_Helper_Test.php b/modules/gallery/tests/Item_Helper_Test.php index 48fdd962..3f80733f 100644 --- a/modules/gallery/tests/Item_Helper_Test.php +++ b/modules/gallery/tests/Item_Helper_Test.php @@ -18,65 +18,30 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Item_Helper_Test extends Unit_Test_Case { - private $_group; - private $_album; - private $_item; - //private $_user; - public function teardown() { - try { - $this->_group->delete(); - } catch (Exception $e) { } - - try { - $this->_album->delete(); - } catch (Exception $e) { } - - //try { - // $this->_user->delete(); - //} catch (Exception $e) { } - } - - public function setup() { - } - - public function viewable_item_test() { - $this->_group = group::create("access_test"); + public function viewable_test() { $root = ORM::factory("item", 1); - $this->_album = album::create($root, rand(), "visible_test"); - $this->_user = user::create("visible_test", "Visible Test", ""); - $this->_user->add($this->_group); - $this->_item = self::_create_random_item($this->_album); - comment::create($this->_item, $this->_user, "This is a comment"); - access::deny(group::everybody(), "view", $this->_album); - $active = user::active(); - - $items = ORM::factory("item") - ->where("id", $this->_album->id) - ->find_all(); - print Database::instance()->last_query() . "\n"; - $items = ORM::factory("item") - ->where("id", $this->_album->id) - ->viewable() - ->find_all(); - print Database::instance()->last_query() . "\n"; + $album = album::create($root, rand(), rand(), rand()); + $item = self::_create_random_item($album); + user::set_active(user::guest()); + + // We can see the item when permissions are granted + access::allow(group::everybody(), "view", $album); + $this->assert_equal( + 1, + ORM::factory("item")->viewable()->where("id", $item->id)->count_all()); + + // We can't see the item when permissions are denied + access::deny(group::everybody(), "view", $album); + $this->assert_equal( + 0, + ORM::factory("item")->viewable()->where("id", $item->id)->count_all()); } - //public function viewable_one_restrictions_test() { - // $item = self::create_random_item(); - // $this->assert_true(!empty($item->created)); - // $this->assert_true(!empty($item->updated)); - //} - //public function viewable_multiple_restrictions_test() { - // $item = self::create_random_item(); - // $this->assert_true(!empty($item->created)); - // $this->assert_true(!empty($item->updated)); - //} - private static function _create_random_item($album) { + // Set all required fields (values are irrelevant) $item = ORM::factory("item"); - /* Set all required fields (values are irrelevant) */ $item->name = rand(); $item->type = "photo"; return $item->add_to_parent($album); -- cgit v1.2.3 From 50c624ed1b5a09d965d4e0f18a32bf3c2a94db15 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 12:20:03 -0700 Subject: Fix active() to not use user::guest() as the fallback for our Session::get() call. --- modules/user/helpers/user.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/user/helpers/user.php b/modules/user/helpers/user.php index 69a6ecb3..40acc2ec 100644 --- a/modules/user/helpers/user.php +++ b/modules/user/helpers/user.php @@ -159,7 +159,12 @@ class user_Core { */ static function active() { // @todo (maybe) cache this object so we're not always doing session lookups. - $user = Session::instance()->get("user", self::guest()); + $user = Session::instance()->get("user", null); + if (!isset($user)) { + // Don't do this as a fallback in the Session::get() call because it can trigger unnecessary + // work. + $user = user::guest(); + } return $user; } -- cgit v1.2.3 From cd1fd4989f394f6e8084b8101a8dbdb3030c52aa Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 12:22:00 -0700 Subject: Add a test for Comment_Model::viewable(). --- modules/comment/tests/Comment_Model_Test.php | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 modules/comment/tests/Comment_Model_Test.php (limited to 'modules') diff --git a/modules/comment/tests/Comment_Model_Test.php b/modules/comment/tests/Comment_Model_Test.php new file mode 100644 index 00000000..f4c68b15 --- /dev/null +++ b/modules/comment/tests/Comment_Model_Test.php @@ -0,0 +1,40 @@ +assert_equal( + 1, + ORM::factory("comment")->viewable()->where("comments.id", $comment->id)->count_all()); + + // We can't see the comment when permissions are denied on the album + access::deny(group::everybody(), "view", $album); + $this->assert_equal( + 0, + ORM::factory("comment")->viewable()->where("comments.id", $comment->id)->count_all()); + } +} -- cgit v1.2.3 From a10063ff68cf5988297dcad889384ab2080c3850 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 12:34:09 -0700 Subject: Add more factory methods for convenience: SafeString::purify() and SafeString::of_safe_html(). Removing SafeString::mark_html_safe() since it's no longer needed. --- modules/gallery/helpers/MY_url.php | 10 +++++----- modules/gallery/libraries/I18n.php | 2 +- modules/gallery/libraries/SafeString.php | 27 +++++++++++++++++++++------ modules/gallery/tests/SafeString_Test.php | 19 +++++++++++-------- modules/gallery/tests/Xss_Security_Test.php | 7 +++++-- 5 files changed, 43 insertions(+), 22 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php index b4b7f352..6092a9d8 100644 --- a/modules/gallery/helpers/MY_url.php +++ b/modules/gallery/helpers/MY_url.php @@ -31,7 +31,7 @@ class url extends url_Core { $uri = model_cache::get("item", $parts[1])->relative_path(); } $url = parent::site($uri . $query, $protocol); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } static function parse_url() { @@ -103,22 +103,22 @@ class url extends url_Core { public static function base($index=false, $protocol=false) { $url = parent::base($index, $protocol); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } public static function current($qs=false) { $url = parent::current($qs); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } public static function file($file, $index=false) { $url = parent::file($file, $index); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } public static function merge(array $arguments) { $url = parent::merge($arguments); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } } diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php index 8dc42e04..a53d5ae9 100644 --- a/modules/gallery/libraries/I18n.php +++ b/modules/gallery/libraries/I18n.php @@ -116,7 +116,7 @@ class I18n_Core { $entry = $this->interpolate($locale, $entry, $values); - return SafeString::of($entry)->mark_html_safe(); + return SafeString::of_safe_html($entry); } private function lookup($locale, $message) { diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 709ab5f6..9a269ed4 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -24,6 +24,7 @@ class SafeString_Core { private $_raw_string; protected $_is_safe_html = false; + protected $_is_purified_html = false; private static $_purifier = null; @@ -44,11 +45,25 @@ class SafeString_Core { } /** - * Marks this string as safe to be used in HTML without any escaping. + * Factory method returning a new SafeString instance after HTML purifying + * the given string. */ - function mark_html_safe() { - $this->_is_safe_html = true; - return $this; + 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; } /** @@ -117,10 +132,10 @@ class SafeString_Core { * @return the string escaped for use in HTML. */ function purified_html() { - if ($this->_is_safe_html) { + if ($this->_is_purified_html) { return $this; } else { - return SafeString::of(self::_purify_for_html($this->_raw_string), true); + return self::purify($this); } } diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 73d82c34..0fc7f6f3 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -25,8 +25,7 @@ class SafeString_Test extends Unit_Test_Case { } public function toString_for_safe_string_test() { - $safe_string = new SafeString("hello

      world

      "); - $safe_string->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello

      world

      "); $this->assert_equal("hello

      world

      ", $safe_string); } @@ -62,7 +61,7 @@ class SafeString_Test extends Unit_Test_Case { } public function for_html_attr_with_safe_html_test() { - $safe_string = SafeString::of('"Foo\'s bar"')->mark_html_safe(); + $safe_string = SafeString::of_safe_html('"Foo\'s bar"'); $attr_string = $safe_string->for_html_attr(); $this->assert_equal('"Foo's bar"', $attr_string); @@ -86,25 +85,29 @@ class SafeString_Test extends Unit_Test_Case { } public function of_safe_html_test() { - $safe_string = SafeString::of("hello

      world

      ")->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello

      world

      "); $this->assert_equal("hello

      world

      ", $safe_string->for_html()); } + public function purify_test() { + $safe_string = SafeString::purify("hello

      world

      "); + $this->assert_equal("hello

      world

      ", $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("hello's

      world

      ")->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello's

      world

      "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

      world

      ", $safe_string_2); $this->assert_equal("hello\\'s

      world<\\/p>", $safe_string_2->for_js()); } public function safestring_of_safestring_preserves_html_safe_status_test() { - $safe_string = SafeString::of("hello's

      world

      ") - ->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello's

      world

      "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

      world

      ", $safe_string_2); $this->assert_equal("hello\\'s

      world<\\/p>", $safe_string_2->for_js()); @@ -112,7 +115,7 @@ class SafeString_Test extends Unit_Test_Case { public function safestring_of_safestring_safe_status_override_test() { $safe_string = new SafeString("hello

      world

      "); - $safe_string_2 = SafeString::of($safe_string)->mark_html_safe(); + $safe_string_2 = SafeString::of_safe_html($safe_string); $this->assert_equal("hello

      world

      ", $safe_string_2); } } diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index e0e5bb86..fd596c69 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -110,10 +110,13 @@ class Xss_Security_Test extends Unit_Test_Case { } 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, "of"), $tokens, $token_number + 2) && + 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); - $frame->expr_append("::of("); + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); $token_number += 3; $token = $tokens[$token_number]; -- cgit v1.2.3 From c01ac42c4604b3b129e8089e0dc683ebd418b380 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 12:48:40 -0700 Subject: Refactor all calls of p::clean() to SafeString::of() and p::purify() to SafeString::purify(). Removing any p::clean() calls for arguments to t() and t2() since their args are wrapped in a SafeString anyway. --- modules/comment/controllers/comments.php | 8 +++--- modules/comment/helpers/comment_rss.php | 8 +++--- .../views/admin_block_recent_comments.html.php | 6 ++--- modules/comment/views/admin_comments.html.php | 10 ++++---- modules/comment/views/comment.html.php | 6 ++--- modules/comment/views/comment.mrss.php | 12 ++++----- modules/comment/views/comments.html.php | 6 ++--- modules/digibug/controllers/digibug.php | 2 +- modules/exif/views/exif_dialog.html.php | 4 +-- modules/g2_import/helpers/g2_import.php | 2 +- .../controllers/admin_advanced_settings.php | 2 +- modules/gallery/controllers/movies.php | 2 +- modules/gallery/controllers/photos.php | 2 +- modules/gallery/controllers/quick.php | 10 ++++---- modules/gallery/helpers/gallery_rss.php | 4 +-- modules/gallery/helpers/gallery_task.php | 4 +-- modules/gallery/helpers/p.php | 29 ---------------------- .../gallery/views/admin_advanced_settings.html.php | 8 +++--- .../gallery/views/admin_block_log_entries.html.php | 2 +- .../views/admin_block_photo_stream.html.php | 4 +-- modules/gallery/views/admin_maintenance.html.php | 2 +- .../views/admin_maintenance_show_log.html.php | 2 +- modules/gallery/views/after_install.html.php | 2 +- modules/gallery/views/move_tree.html.php | 8 +++--- modules/gallery/views/permissions_browse.html.php | 4 +-- modules/gallery/views/permissions_form.html.php | 2 +- modules/gallery/views/simple_uploader.html.php | 6 ++--- modules/info/views/info_block.html.php | 10 ++++---- .../notification/views/comment_published.html.php | 12 ++++----- modules/notification/views/item_added.html.php | 8 +++--- modules/notification/views/item_deleted.html.php | 6 ++--- modules/notification/views/item_updated.html.php | 12 ++++----- modules/organize/controllers/organize.php | 10 ++++---- modules/organize/views/organize.html.php | 2 +- modules/organize/views/organize_album.html.php | 2 +- modules/rss/views/feed.mrss.php | 14 +++++------ modules/search/views/search.html.php | 10 ++++---- .../server_add/controllers/admin_server_add.php | 4 +-- modules/server_add/views/server_add_tree.html.php | 2 +- .../views/server_add_tree_dialog.html.php | 6 ++--- modules/tag/controllers/admin_tags.php | 8 +++--- modules/tag/helpers/tag_rss.php | 2 +- modules/tag/views/admin_tags.html.php | 2 +- modules/tag/views/tag_cloud.html.php | 2 +- modules/user/controllers/admin_users.php | 14 +++++------ modules/user/controllers/login.php | 4 +-- modules/user/controllers/logout.php | 4 +-- modules/user/controllers/password.php | 2 +- modules/user/views/admin_users.html.php | 8 +++--- modules/user/views/admin_users_group.html.php | 8 +++--- modules/user/views/login.html.php | 6 ++--- modules/user/views/reset_password.html.php | 2 +- system/helpers/request.php | 2 +- themes/default/views/album.html.php | 4 +-- themes/default/views/dynamic.html.php | 4 +-- themes/default/views/header.html.php | 4 +-- themes/default/views/movie.html.php | 4 +-- themes/default/views/page.html.php | 8 +++--- themes/default/views/photo.html.php | 4 +-- 59 files changed, 159 insertions(+), 188 deletions(-) delete mode 100644 modules/gallery/helpers/p.php (limited to 'modules') 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 ab3d2283..d0f15010 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; } @@ -53,13 +53,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 @@
    • "> " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="32" height="32" /> created) ?> %author_name said %comment_text', - 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))); ?>
    • diff --git a/modules/comment/views/admin_comments.html.php b/modules/comment/views/admin_comments.html.php index 9fe7164b..b27e3166 100644 --- a/modules/comment/views/admin_comments.html.php +++ b/modules/comment/views/admin_comments.html.php @@ -108,12 +108,12 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> -

      author_name()) ?>

      +

      author_name()) ?>

      created) ?>

      - text)) ?> + text)) ?>
        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 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> gallery::date_time($comment->created), - "author_name" => p::clean($comment->author_name()))) ?> + "author_name" => SafeString::of($comment->author_name()))) ?>

        - text)) ?> + text)) ?>
        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"> Gallery 3 - <?= p::clean($feed->title) ?> + <?= SafeString::of($feed->title) ?> uri ?> - description) ?> + description) ?> en-us @@ -22,14 +22,14 @@ children as $child): ?> - <?= p::purify($child->title) ?> - item_uri) ?> - author) ?> + <?= SafeString::purify($child->title) ?> + item_uri) ?> + author) ?> item_uri ?> pub_date ?> text)) ?>

        +

        text)) ?>

        diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index f7251389..7941b7da 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -12,16 +12,16 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> %name said', array("date" => date("Y-M-d H:i:s", $comment->created), - "name" => p::clean($comment->author_name()))); ?> + "name" => SafeString::of($comment->author_name()))); ?>

        - text)) ?> + text)) ?>
        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 @@ - + - + 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/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", "id\">view"); 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", "id\">view"); 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 de027c1b..98a5bf9f 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -89,7 +89,7 @@ class Quick_Controller extends Controller { access::required("view", $item->parent()); access::required("edit", $item->parent()); - $msg = t("Made %title this album's cover", array("title" => p::purify($item->title))); + $msg = t("Made %title this album's cover", array("title" => SafeString::purify($item->title))); item::make_album_cover($item); message::success($msg); @@ -105,10 +105,10 @@ class Quick_Controller extends Controller { if ($item->is_album()) { print t( "Delete the album %title? 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 %title?", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } $form = item::get_delete_form($item); @@ -122,9 +122,9 @@ class Quick_Controller extends Controller { access::required("edit", $item); if ($item->is_album()) { - $msg = t("Deleted album %title", array("title" => p::purify($item->title))); + $msg = t("Deleted album %title", array("title" => SafeString::purify($item->title))); } else { - $msg = t("Deleted photo %title", array("title" => p::purify($item->title))); + $msg = t("Deleted photo %title", array("title" => SafeString::purify($item->title))); } $parent = $item->parent(); diff --git a/modules/gallery/helpers/gallery_rss.php b/modules/gallery/helpers/gallery_rss.php index 7daf6170..be555296 100644 --- a/modules/gallery/helpers/gallery_rss.php +++ b/modules/gallery/helpers/gallery_rss.php @@ -52,9 +52,9 @@ class gallery_rss_Core { ->viewable() ->descendants($limit, $offset, "photo"); $feed->max_pages = ceil($item->viewable()->descendants_count("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 e852c086..00000000 --- a/modules/gallery/helpers/p.php +++ /dev/null @@ -1,29 +0,0 @@ -purified_html(); - } -} 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 @@ module_name == "gallery" && $var->name == "_cache") continue ?> module_name ?> - name) ?> + name) ?> - module_name/" . p::clean($var->name)) ?>" + module_name/" . SafeString::of($var->name)) ?>" class="gDialogLink" - title=" p::clean($var->name), "module_name" => $var->module_name)) ?>"> + title=" $var->name, "module_name" => $var->module_name)) ?>"> value): ?> - value) ?> + value) ?> 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 @@
        • - user_id") ?>">user->name) ?> + user_id") ?>">user->name) ?> timestamp) ?> message ?> 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 @@
          • - id") ?>" title="title) ?>"> + id") ?>" title="title) ?>"> width, $photo->height, 72) ?> - src="thumb_url() ?>" alt="title) ?>" /> + src="thumb_url() ?>" alt="title) ?>" />
          • diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index 450eb754..a4db38ce 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -90,7 +90,7 @@ status ?> - owner()->name) ?> + owner()->name) ?> 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();

            name ?>

            -
            get_log()) ?>
            +
            get_log()) ?>
            diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index e4842163..2cf8ec8f 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -8,7 +8,7 @@

            - %user_name 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))) ?> + %user_name account. The very first thing you should do is to change your password to something that you'll remember.", array("user_name" => $user->name)) ?>

            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 @@ thumb_img(array(), 25); ?> is_descendant($parent)): ?> - title) ?> + title) ?> - title) ?> + title) ?>

            • thumb_img(array(), 25); ?> is_descendant($child)): ?> - title) ?> + title) ?> - title) ?> + title) ?>
            • diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php index 888a27f7..9ea0da25 100644 --- a/modules/gallery/views/permissions_browse.html.php +++ b/modules/gallery/views/permissions_browse.html.php @@ -35,14 +35,14 @@
            • - title) ?> + title) ?>
              • - title) ?> + title) ?>
                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 @@ - name) ?> + name) ?> diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index 38ac518c..56e568f6 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -6,7 +6,7 @@
                ">
                - p::purify($item->title))) ?> + SafeString::purify($item->title))) ?>
                @@ -26,9 +26,9 @@

                  parents() as $parent): ?> -
                • title) ?>
                • +
                • title) ?>
                • -
                • title) ?>
                • +
                • title) ?>

                diff --git a/modules/info/views/info_block.html.php b/modules/info/views/info_block.html.php index f86ae39d..365a1021 100644 --- a/modules/info/views/info_block.html.php +++ b/modules/info/views/info_block.html.php @@ -2,18 +2,18 @@

                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 2af1b879..066efbba 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -74,7 +74,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 542b8b8b..54c4847d 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -68,16 +68,16 @@ " title="" - alt="name) ?>" + alt="name) ?>" width="20" height="20" /> - name) ?> + name) ?> - full_name) ?> + full_name) ?> - email) ?> + email) ?> 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 @@

                - name) ?> + name) ?> special): ?> id") ?>" - title=" p::clean($group->name))) ?>" + title=" $group->name)) ?>" class="gDialogLink gButtonLink ui-state-default ui-corner-all"> @@ -17,12 +17,12 @@

                  @@ -16,7 +16,7 @@ width="thumb_width ?>" height="thumb_height ?>" /> -

                  title) ?>

                  +

                  title) ?>

                  thumb_bottom($child) ?> diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 66c80ded..1f25a626 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -15,8 +15,8 @@ movie_img(array("class" => "gMovie", "id" => "gMovieId-{$item->id}")) ?>
                  -

                  title) ?>

                  -
                  description)) ?>
                  +

                  title) ?>

                  +
                  description)) ?>
                  diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index 56e568f6..fc426e8f 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -82,27 +82,26 @@ diff --git a/modules/organize/views/organize.html.php b/modules/organize/views/organize.html.php index 1182a887..d2f0aa8c 100644 --- a/modules/organize/views/organize.html.php +++ b/modules/organize/views/organize.html.php @@ -1,16 +1,16 @@ script("gallery.dialog.js") ?> script("superfish/js/superfish.js") ?> diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 1f25a626..75d51eff 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -20,7 +20,7 @@
            photo_bottom() ?>
      diff --git a/themes/default/views/page.html.php b/themes/default/views/page.html.php index ea2be37b..8d9f0caa 100644 --- a/themes/default/views/page.html.php +++ b/themes/default/views/page.html.php @@ -51,7 +51,7 @@ script("gallery.common.js") ?> script("gallery.dialog.js") ?> script("gallery.form.js") ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 1f92e9ba..fcf597cf 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ photo_bottom() ?>
      -- cgit v1.2.3 From f327b4ad38923d40fcd6540467604cb0f24cd8bf Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 14:24:52 -0700 Subject: Fix link in l10n UI (for SafeString changes) --- modules/gallery/controllers/admin_languages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php index 6dc242c6..68be709e 100644 --- a/modules/gallery/controllers/admin_languages.php +++ b/modules/gallery/controllers/admin_languages.php @@ -111,7 +111,7 @@ class Admin_Languages_Controller extends Admin_Controller { $group->input("api_key") ->label(empty($api_key) ? t("This is a unique key that will allow you to send translations to the remote server. To get your API key go to %server-link.", - array("server-link" => html::anchor($server_link))) + array("server-link" => SafeString::of_safe_html(html::anchor($server_link)))) : t("API Key")) ->value($api_key) ->error_messages("invalid", t("The API key you provided is invalid.")); -- cgit v1.2.3 From c4d5ecde66c7bffde2259b9815c050e6a4d8f333 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 14:38:47 -0700 Subject: L10n fixes for the admin_languages page, and JS/XSS cleanup of the organize views. --- modules/gallery/views/admin_languages.html.php | 21 +++++++++++++-------- modules/organize/views/organize_dialog.html.php | 2 +- modules/organize/views/organize_tree.html.php | 6 +++--- 3 files changed, 17 insertions(+), 12 deletions(-) (limited to 'modules') diff --git a/modules/gallery/views/admin_languages.html.php b/modules/gallery/views/admin_languages.html.php index 4025437a..4bee9bb1 100644 --- a/modules/gallery/views/admin_languages.html.php +++ b/modules/gallery/views/admin_languages.html.php @@ -36,11 +36,11 @@ - " /> + for_html_attr() ?>" />
      -

      p::purify($album->title))) ?>

      +

      SafeString::purify($album->title))) ?>

      diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 36f900ac..387d5977 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -5,7 +5,7 @@ - title) ?> + title) ?>
        @@ -17,7 +17,7 @@ " ref="id ?>"> - title) ?> + title) ?> id == $album->id): ?> @@ -29,7 +29,7 @@ - title) ?> + title) ?> -- cgit v1.2.3 From a5ddef021c1ca4920e40c0657de082ae0d7008ee Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 29 Aug 2009 15:03:46 -0700 Subject: Fix invalida syntax on trying to parse the progress bar percentage --- modules/gallery/views/admin_maintenance_task.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/views/admin_maintenance_task.html.php b/modules/gallery/views/admin_maintenance_task.html.php index 0eb0b38c..509e87b5 100644 --- a/modules/gallery/views/admin_maintenance_task.html.php +++ b/modules/gallery/views/admin_maintenance_task.html.php @@ -4,7 +4,7 @@ var animation = null; var delta = 1; animate_progress_bar = function() { - var current_value = Number($(".gProgressBar div").css("width").replace("%", "")); + var current_value = parseInt($(".gProgressBar div").css("width").replace("%", "")); if (target_value > current_value) { // speed up delta = Math.min(delta + 0.04, 3); -- cgit v1.2.3 From 0aceba6f48e5542d3edfbb1f195af50187adbac4 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 29 Aug 2009 15:20:27 -0700 Subject: Fix for ticket #628: 1) increased gallery module version to 11 2) added image_sharpened parameter to the gallery module 3) sharpen all resizes. --- modules/gallery/helpers/gallery_installer.php | 9 ++++++++- modules/gallery/helpers/graphics.php | 5 +++++ modules/gallery/module.info | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index a212ef85..40830bc0 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -223,6 +223,7 @@ class gallery_installer { module::set_var("gallery", "resize_size", 640); module::set_var("gallery", "default_locale", "en_US"); module::set_var("gallery", "image_quality", 75); + module::set_var("gallery", "image_sharpen", 15); // Add rules for generating our thumbnails and resizes graphics::add_rule( @@ -259,7 +260,7 @@ class gallery_installer { module::set_var("gallery", "show_credits", 1); // @todo this string needs to be picked up by l10n_scanner module::set_var("gallery", "credits", "Powered by Gallery %version"); - module::set_version("gallery", 10); + module::set_version("gallery", 11); } static function upgrade($version) { @@ -336,6 +337,12 @@ class gallery_installer { module::set_version("gallery", $version = 10); } + + if ($version == 10) { + module::set_var("gallery", "image_sharpen", 15); + + module::set_version("gallery", $version = 11); + } } static function uninstall() { diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 7dc46eeb..2892011f 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -206,10 +206,15 @@ class graphics_Core { // Image would get upscaled; do nothing copy($input_file, $output_file); } else { + try { Image::factory($input_file) ->resize($options["width"], $options["height"], $options["master"]) ->quality(module::get_var("gallery", "image_quality")) + ->sharpen(module::get_var("gallery", "image_sharpen")) ->save($output_file); + } catch (Exception $e) { + Kohana::log("error", $e->getMessage()); + } } module::event("graphics_resize_completed", $input_file, $output_file, $options); diff --git a/modules/gallery/module.info b/modules/gallery/module.info index dfb1a7a2..6b9dd1ba 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,3 +1,3 @@ name = "Gallery 3" description = "Gallery core application" -version = 10 +version = 11 -- cgit v1.2.3 From 0204617b602183a3e157bc7e23c617acd22a5212 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 15:41:02 -0700 Subject: XSS fixes --- modules/gallery/views/admin_maintenance.html.php | 2 +- modules/rss/views/rss_block.html.php | 2 +- modules/server_add/views/admin_server_add.html.php | 4 ++-- modules/server_add/views/server_add_tree.html.php | 4 ++-- modules/tag/views/admin_tags.html.php | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'modules') diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index a0a6a19e..a1f7b126 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -164,7 +164,7 @@ status ?> - owner()->name ?> + owner()->name) ?> done): ?> diff --git a/modules/rss/views/rss_block.html.php b/modules/rss/views/rss_block.html.php index 39921d7d..cd8db89d 100644 --- a/modules/rss/views/rss_block.html.php +++ b/modules/rss/views/rss_block.html.php @@ -5,7 +5,7 @@ - + diff --git a/modules/server_add/views/admin_server_add.html.php b/modules/server_add/views/admin_server_add.html.php index 30ab3536..c4439bda 100644 --- a/modules/server_add/views/admin_server_add.html.php +++ b/modules/server_add/views/admin_server_add.html.php @@ -11,12 +11,12 @@ diff --git a/modules/server_add/views/server_add_tree.html.php b/modules/server_add/views/server_add_tree.html.php index b68544ec..2f65a590 100644 --- a/modules/server_add/views/server_add_tree.html.php +++ b/modules/server_add/views/server_add_tree.html.php @@ -10,7 +10,7 @@
      • - +
          @@ -22,7 +22,7 @@ ondblclick="open_dir($(this).attr('file'))" - file="" + file=" '\\"')) ?>" > diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php index 5bd23112..30dd0728 100644 --- a/modules/tag/views/admin_tags.html.php +++ b/modules/tag/views/admin_tags.html.php @@ -32,7 +32,7 @@ name, 0, 1)) ?> - +
            $tags_per_column): /* new column */ ?> @@ -42,7 +42,7 @@
          - +
            -- cgit v1.2.3 From a1ce2d3f0aff6dcb7149f2d7327a10079e5c78f8 Mon Sep 17 00:00:00 2001 From: jhilden Date: Sat, 29 Aug 2009 19:19:04 -0400 Subject: you can close the l10n client directly from its interface now, without going back to the languages admin page --- modules/gallery/js/l10n_client.js | 13 +++++++++++++ modules/gallery/views/l10n_client.html.php | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/js/l10n_client.js b/modules/gallery/js/l10n_client.js index 80fe166b..35986e5a 100644 --- a/modules/gallery/js/l10n_client.js +++ b/modules/gallery/js/l10n_client.js @@ -205,6 +205,19 @@ Gallery.behaviors.l10nClient = function(context) { Gallery.l10nClient.toggle(0); } }); + + // Close the l10n client using an AJAX call and refreshing the page + $('#gCloseL10n').click(function(event) { + $.ajax({ + type: "GET", + url: toggle_l10n_mode_url, + data: "csrf=" + csrf, + success: function() { + window.location.reload(true); + } + }); + event.preventDefault(); + }); // Register keybindings using jQuery hotkeys // TODO: Either remove hotkeys code or add query.hotkeys.js. diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php index 5ee7eca3..6c440b68 100644 --- a/modules/gallery/views/l10n_client.html.php +++ b/modules/gallery/views/l10n_client.html.php @@ -3,7 +3,8 @@
            _ - X + " + href="">X

            get('show_all_l10n_messages')): ?> @@ -76,5 +77,7 @@ var MSG_CLOSE_X = ""; var l10n_client_data = ; var plural_forms = ; + var toggle_l10n_mode_url = ""; + var csrf = "";

            -- cgit v1.2.3 From b4b638be44375c93f5222c7b48ed547845d6d7e5 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 16:28:30 -0700 Subject: Undo url helper changes - url methods no longer return a SafeString. Adding SafeString::of_safe_html() calls where urls are passed as parameters to t() and t2(). --- modules/akismet/helpers/akismet.php | 2 +- modules/digibug/views/admin_digibug.html.php | 2 +- modules/exif/helpers/exif.php | 2 +- modules/g2_import/views/admin_g2_import.html.php | 10 ++++----- modules/gallery/helpers/MY_url.php | 24 +--------------------- modules/gallery/helpers/graphics.php | 2 +- modules/gallery/tests/Xss_Security_Test.php | 15 +++++++++++--- modules/gallery/views/admin_block_welcome.html.php | 10 ++++----- modules/gallery/views/upgrader.html.php | 2 +- modules/recaptcha/helpers/recaptcha.php | 2 +- modules/search/helpers/search.php | 2 +- modules/server_add/helpers/server_add.php | 2 +- modules/user/views/reset_password.html.php | 4 +++- system/helpers/request.php | 2 +- 14 files changed, 35 insertions(+), 46 deletions(-) (limited to 'modules') diff --git a/modules/akismet/helpers/akismet.php b/modules/akismet/helpers/akismet.php index db45a6ab..abca78d2 100644 --- a/modules/akismet/helpers/akismet.php +++ b/modules/akismet/helpers/akismet.php @@ -94,7 +94,7 @@ class akismet_Core { if (empty($api_key)) { site_status::warning( t("Akismet is not quite ready! Please provide an API Key", - array("url" => url::site("admin/akismet"))), + array("url" => SafeString::of_safe_html(url::site("admin/akismet")))), "akismet_config"); } else { site_status::clear("akismet_config"); diff --git a/modules/digibug/views/admin_digibug.html.php b/modules/digibug/views/admin_digibug.html.php index 7e4436ff..5f27a3fd 100644 --- a/modules/digibug/views/admin_digibug.html.php +++ b/modules/digibug/views/admin_digibug.html.php @@ -16,7 +16,7 @@

            register with Digibug and enter your Digibug id in the Advanced Settings page you can make money off of your photos!", array("signup_url" => "http://www.digibug.com/signup.php", - "advanced_settings_url" => url::site("admin/advanced_settings"))) ?> + "advanced_settings_url" => SafeString::of_safe_html(url::site("admin/advanced_settings")))) ?>

      diff --git a/modules/exif/helpers/exif.php b/modules/exif/helpers/exif.php index 20ecd0cb..d4e60338 100644 --- a/modules/exif/helpers/exif.php +++ b/modules/exif/helpers/exif.php @@ -164,7 +164,7 @@ class exif_Core { if ($remaining) { site_status::warning( t('Your Exif index needs to be updated. Fix this now', - array("url" => url::site("admin/maintenance/start/exif_task::update_index?csrf=__CSRF__"))), + array("url" => SafeString::of_safe_html(url::site("admin/maintenance/start/exif_task::update_index?csrf=__CSRF__")))), "exif_index_out_of_date"); } } diff --git a/modules/g2_import/views/admin_g2_import.html.php b/modules/g2_import/views/admin_g2_import.html.php index da2bb5d1..f53510f6 100644 --- a/modules/g2_import/views/admin_g2_import.html.php +++ b/modules/g2_import/views/admin_g2_import.html.php @@ -37,9 +37,9 @@
    • Using the same value will speed up your import.", - array("g2_pixels" => $g2_sizes["thumb"]["size"], - "g3_pixels" => $thumb_size, - "url" => url::site("admin/theme_options"))) ?> + array("g2_pixels" => $g2_sizes["thumb"]["size"], + "g3_pixels" => $thumb_size, + "url" => SafeString::of_safe_html(url::site("admin/theme_options")))) ?>
    • @@ -47,8 +47,8 @@
    • Using the same value will speed up your import.", array("g2_pixels" => $g2_sizes["resize"]["size"], - "g3_pixels" => $resize_size, - "url" => url::site("admin/theme_options"))) ?> + "g3_pixels" => $resize_size, + "url" => SafeString::of_safe_html(url::site("admin/theme_options")))) ?>
    • diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php index 6092a9d8..c4967c52 100644 --- a/modules/gallery/helpers/MY_url.php +++ b/modules/gallery/helpers/MY_url.php @@ -30,8 +30,7 @@ class url extends url_Core { if ($parts[0] == "albums" || $parts[0] == "photos") { $uri = model_cache::get("item", $parts[1])->relative_path(); } - $url = parent::site($uri . $query, $protocol); - return SafeString::of_safe_html($url); + return parent::site($uri . $query, $protocol); } static function parse_url() { @@ -100,25 +99,4 @@ 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/graphics.php b/modules/gallery/helpers/graphics.php index 7dc46eeb..fbb85bec 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -442,7 +442,7 @@ class graphics_Core { if (!module::get_var("gallery", "graphics_toolkit")) { site_status::warning( t("Graphics toolkit missing! Please choose a toolkit", - array("url" => url::site("admin/graphics"))), + array("url" => SafeString::of_safe_html(url::site("admin/graphics")))), "missing_graphics_toolkit"); } } diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 690dc760..a2d3d59b 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -130,14 +130,14 @@ class Xss_Security_Test extends Unit_Test_Case { $token = $tokens[$token_number]; } } else if ($token[1] == "url") { - // url methods return a SafeString + // url methods return safe HTML 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); + $frame->is_safe_html(true); $method = $tokens[$token_number + 2][1]; $frame->expr_append("::$method("); @@ -203,7 +203,8 @@ class Xss_Security_Test extends Unit_Test_Case { $state = "CLEAN"; } } else { - if ($frame->is_safestring() || $frame->purified_html_called() || $frame->for_html_called()) { + if ($frame->is_safe_html() || $frame->is_safestring() || + $frame->purified_html_called() || $frame->for_html_called()) { $state = "CLEAN"; } } @@ -259,6 +260,7 @@ class Xss_Security_Test_Frame { private $_for_html_called = false; private $_purified_html_called = false; private $_json_encode_called = false; + private $_is_safe_html = false; private $_line; function __construct($line_number, $in_script_block) { @@ -288,6 +290,13 @@ class Xss_Security_Test_Frame { return $this->_is_safestring; } + function is_safe_html($new_val=NULL) { + if ($new_val !== NULL) { + $this->_is_safe_html = (bool) $new_val; + } + return $this->_is_safe_html; + } + function json_encode_called($new_val=NULL) { if ($new_val !== NULL) { $this->_json_encode_called = (bool) $new_val; diff --git a/modules/gallery/views/admin_block_welcome.html.php b/modules/gallery/views/admin_block_welcome.html.php index 38d2bd56..c6ccdbf3 100644 --- a/modules/gallery/views/admin_block_welcome.html.php +++ b/modules/gallery/views/admin_block_welcome.html.php @@ -5,16 +5,16 @@
      • graphics and language settings.", - array("graphics_url" => url::site("admin/graphics"), - "language_url" => url::site("admin/languages"))) ?> + array("graphics_url" => SafeString::of_safe_html(url::site("admin/graphics")), + "language_url" => SafeString::of_safe_html(url::site("admin/languages")))) ?>
      • choose a theme, or customize the way it looks.", - array("theme_url" => url::site("admin/themes"), - "theme_options_url" => url::site("admin/theme_options"))) ?> + array("theme_url" => SafeString::of_safe_html(url::site("admin/themes")), + "theme_options_url" => SafeString::of_safe_html(url::site("admin/theme_options")))) ?>
      • install modules to add cool features!", - array("modules_url" => url::site("admin/modules"))) ?> + array("modules_url" => SafeString::of_safe_html(url::site("admin/modules")))) ?>
      diff --git a/modules/gallery/views/upgrader.html.php b/modules/gallery/views/upgrader.html.php index 37578855..ccc86da8 100644 --- a/modules/gallery/views/upgrader.html.php +++ b/modules/gallery/views/upgrader.html.php @@ -18,7 +18,7 @@

      Gallery is up to date.", - array("url" => url::site("albums/1"))) ?> + array("url" => SafeString::of_safe_html(url::site("albums/1")))) ?>

      diff --git a/modules/recaptcha/helpers/recaptcha.php b/modules/recaptcha/helpers/recaptcha.php index 501dd972..35d9febd 100644 --- a/modules/recaptcha/helpers/recaptcha.php +++ b/modules/recaptcha/helpers/recaptcha.php @@ -43,7 +43,7 @@ class recaptcha_Core { if (empty($public_key) || empty($private_key)) { site_status::warning( t("reCAPTCHA is not quite ready! Please configure the reCAPTCHA Keys", - array("url" => url::site("admin/recaptcha"))), + array("url" => SafeString::of_safe_html(url::site("admin/recaptcha")))), "recaptcha_config"); } else { site_status::clear("recaptcha_config"); diff --git a/modules/search/helpers/search.php b/modules/search/helpers/search.php index 355c4493..4be04039 100644 --- a/modules/search/helpers/search.php +++ b/modules/search/helpers/search.php @@ -58,7 +58,7 @@ class search_Core { if ($remaining) { site_status::warning( t('Your search index needs to be updated. Fix this now', - array("url" => url::site("admin/maintenance/start/search_task::update_index?csrf=__CSRF__"))), + array("url" => SafeString::of_safe_html(url::site("admin/maintenance/start/search_task::update_index?csrf=__CSRF__")))), "search_index_out_of_date"); } } diff --git a/modules/server_add/helpers/server_add.php b/modules/server_add/helpers/server_add.php index 74f51ad9..57afac12 100644 --- a/modules/server_add/helpers/server_add.php +++ b/modules/server_add/helpers/server_add.php @@ -25,7 +25,7 @@ class server_add_Core { if (empty($paths)) { site_status::warning( t("Server Add needs configuration. Configure it now!", - array("url" => url::site("admin/server_add"))), + array("url" => SafeString::of_safe_html(url::site("admin/server_add")))), "server_add_configuration"); } else { site_status::clear("server_add_configuration"); diff --git a/modules/user/views/reset_password.html.php b/modules/user/views/reset_password.html.php index 3dc7aebf..6fa92d54 100644 --- a/modules/user/views/reset_password.html.php +++ b/modules/user/views/reset_password.html.php @@ -9,7 +9,9 @@ $user->full_name ? $user->full_name : $user->name)) ?>

      - %site_url. If you made this request, you can confirm it by clicking this link. 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)) ?> + %site_url. If you made this request, you can confirm it by clicking this link. If you didn't request this password reset, it's ok to ignore this mail.", + array("site_url" => SafeString::of_safe_html(url::base(false, "http")), + "confirm_url" => $confirm_url)) ?>

      diff --git a/system/helpers/request.php b/system/helpers/request.php index 15b8edfa..4203d0e5 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, (string) url::base(FALSE)) === 0) + if (strpos($ref, url::base(FALSE)) === 0) { // Remove the base URL from the referrer $ref = substr($ref, strlen(url::base(FALSE))); -- cgit v1.2.3 From 483d8df91b443a20a614eb5864cabb2a66ac72d2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 16:33:22 -0700 Subject: Change the organize tree to expand/collapse. It doesn't properly open up to the album that you're viewing, and if you move a photo to a different album it'll reload the entire album tree. --- modules/organize/controllers/organize.php | 18 +++++----- modules/organize/js/organize.js | 26 ++++++++++++++ modules/organize/views/organize_dialog.html.php | 1 + modules/organize/views/organize_tree.html.php | 46 +++++++------------------ 4 files changed, 47 insertions(+), 44 deletions(-) (limited to 'modules') diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 2b966657..3cbcfb28 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -25,7 +25,7 @@ class Organize_Controller extends Controller { $v = new View("organize_dialog.html"); $v->album = $album; - $v->album_tree = self::_tree($album); + $v->album_tree = self::_tree(ORM::factory("item", 1)); $v->micro_thumb_grid = self::_get_micro_thumb_grid($album, 0); print $v; } @@ -50,7 +50,7 @@ class Organize_Controller extends Controller { } print json_encode( - array("tree" => self::_tree($album)->__toString(), + array("tree" => self::_tree(ORM::factory("item", 1))->__toString(), "grid" => self::_get_micro_thumb_grid($album, 0)->__toString())); } @@ -132,17 +132,15 @@ class Organize_Controller extends Controller { return $v; } + public function tree($album_id) { + $album = ORM::factory("item", $album_id); + access::required("view", $album); + print self::_tree($album); + } + private static function _tree($album) { $v = new View("organize_tree.html"); - $v->parents = $album->parents(); $v->album = $album; - - if ($album->id == 1) { - $v->peers = array($album); - } else { - $v->peers = $album->parent()->children(null, 0, array("type" => "album")); - } - return $v; } } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 04e14a2f..3dbd0c89 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -159,8 +159,34 @@ $(".gMicroThumbGridCell").mousemove($.organize.mouse_move_handler); $(".gOrganizeAlbum").droppable($.organize.branch_droppable); $(".gAlbumText").click($.organize.show_album); + $("#gOrganizeAlbumTree .ui-icon-plus,#gOrganizeAlbumTree .ui-icon-minus").click($.organize.toggle_branch); }, + toggle_branch: function(event) { + event.preventDefault(); + var target = $(event.currentTarget); + var branch = $(target).parent(); + var id = $(event.currentTarget).parent().attr("ref"); + + if ($(target).hasClass("ui-icon-plus")) { + // Expanding + if (!branch.find("ul").length) { + $.get(tree_url.replace("__ALBUM_ID__", id), { }, + function(data) { + branch.replaceWith(data); + $.organize.set_handlers(); + } + ); + } else { + branch.find("ul:eq(0)").slideDown(); + } + } else { + // Contracting + branch.find("ul:eq(0)").slideUp(); + } + $(target).toggleClass("ui-icon-plus"); + $(target).toggleClass("ui-icon-minus"); + }, /** * When the text of a selection is clicked, then show that albums contents diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index b03c066c..d4196460 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -3,6 +3,7 @@ var move_url = ""; var rearrange_url = ""; var sort_order_url = ""; + var tree_url = "";

      p::purify($album->title))) ?>

      diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 36f900ac..4677234c 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,44 +1,22 @@ - -
    • " - ref="id ?>"> +
    • " + ref="id ?>"> - - title) ?> + + title) ?> -
        - - - -
      • " - ref="id ?>"> - "> +
          + children(null, 0, array("type" => "album")) as $child): ?> +
        • " + ref="id ?>"> + - " - ref="id ?>"> - title) ?> + + title) ?> - - id == $album->id): ?> -
            - children(null, 0, array("type" => "album")) as $child): ?> -
          • " - ref="id ?>"> - - - - title) ?> - -
          • - -
          -
        • - -
      • - + -- cgit v1.2.3 From 878b9c91b234f464eb9e1a3bdfbd0e6285a1a0e7 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 16:38:53 -0700 Subject: Remove try/catch in resize() since that will swallow any exceptions that we generate when resizing. --- modules/gallery/helpers/graphics.php | 4 ---- 1 file changed, 4 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 2892011f..a20c58dd 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -206,15 +206,11 @@ class graphics_Core { // Image would get upscaled; do nothing copy($input_file, $output_file); } else { - try { Image::factory($input_file) ->resize($options["width"], $options["height"], $options["master"]) ->quality(module::get_var("gallery", "image_quality")) ->sharpen(module::get_var("gallery", "image_sharpen")) ->save($output_file); - } catch (Exception $e) { - Kohana::log("error", $e->getMessage()); - } } module::event("graphics_resize_completed", $input_file, $output_file, $options); -- cgit v1.2.3 From 4bc7165dab267311407294b11a77e6c2689ad4a1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 16:42:33 -0700 Subject: Delete obsolete comment and tighten the code in site_menu(). --- modules/server_add/helpers/server_add_event.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'modules') diff --git a/modules/server_add/helpers/server_add_event.php b/modules/server_add/helpers/server_add_event.php index 6b21ec2e..b9dd8c28 100644 --- a/modules/server_add/helpers/server_add_event.php +++ b/modules/server_add/helpers/server_add_event.php @@ -31,15 +31,11 @@ class server_add_event_Core { $paths = unserialize(module::get_var("server_add", "authorized_paths")); if ($item && user::active()->admin && $item->is_album() && !empty($paths)) { - // This is a little tricky. Normally there's an "Add Photo" menu option, but we want to - // turn that into a dropdown if there are two different ways to add things. Do that in a - // portable way for now. If we find ourselves duplicating this pattern, we should make an - // API method for this. - $add_menu = $menu->get("add_menu"); - $add_menu->append(Menu::factory("dialog") - ->id("server_add") - ->label(t("Server add")) - ->url(url::site("server_add/browse/$item->id"))); + $menu->get("add_menu") + ->append(Menu::factory("dialog") + ->id("server_add") + ->label(t("Server add")) + ->url(url::site("server_add/browse/$item->id"))); } } } -- cgit v1.2.3 From 952c8856098dcfd9673d344fc71be85b303c8fb1 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 22:31:23 -0700 Subject: Adding html::clean(), ::purify(), etc. --- modules/gallery/helpers/MY_html.php | 91 +++++++++++++++++++++++++++++ modules/gallery/tests/Html_Helper_Test.php | 55 +++++++++++++++++ modules/gallery/tests/Xss_Security_Test.php | 86 ++++++++++++--------------- 3 files changed, 182 insertions(+), 50 deletions(-) create mode 100644 modules/gallery/helpers/MY_html.php create mode 100644 modules/gallery/tests/Html_Helper_Test.php (limited to 'modules') diff --git a/modules/gallery/helpers/MY_html.php b/modules/gallery/helpers/MY_html.php new file mode 100644 index 00000000..eb388811 --- /dev/null +++ b/modules/gallery/helpers/MY_html.php @@ -0,0 +1,91 @@ + + *
        + * + */ + static function clean($html) { + return new SafeString($html); + } + + /** + * Returns a string that is safe to be used in HTML (XSS protection), + * purifying (filtering) the given HTML to ensure that the result contains + * only non-malicious HTML. + * + * Example:
        +   *   
        title) ?> + *
        + */ + static function purify($html) { + return SafeString::purify($html); + } + + /** + * Flags the given string as safe to be used in HTML (free of malicious HTML/JS). + * + * Example:
        +   *   // Parameters to t() are automatically escaped by default.
        +   *   // If the parameter is marked as safe, it won't get escaped.
        +   *   t('Go there',
        +   *     array("url" => html::mark_safe(url::current())))
        +   * 
        + */ + static function mark_safe($html) { + return SafeString::of_safe_html($html); + } + + /** + * Escapes the given string for use in JavaScript. + * + * Example:
        +   *   
        +   * 
        + * @return the string escaped for use in HTML attributes. + */ + static function clean_attribute($string) { + return self::clean($string)->for_html_attr(); + } +} diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php new file mode 100644 index 00000000..4d934ad5 --- /dev/null +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -0,0 +1,55 @@ +world

        "); + $this->assert_equal("hello <p >world</p>", + $safe_string); + $this->assert_true($safe_string instanceof SafeString); + } + + public function purify_test() { + $safe_string = html::purify("hello

        world

        "); + $this->assert_equal("hello

        world

        ", + $safe_string); + $this->assert_true($safe_string instanceof SafeString); + } + + public function mark_safe_test() { + $safe_string = html::mark_safe("hello

        world

        "); + $this->assert_true($safe_string instanceof SafeString); + $safe_string_2 = html::clean($safe_string); + $this->assert_equal("hello

        world

        ", + $safe_string_2); + } + + public function escape_for_js_test() { + $string = html::escape_for_js("hello's

        world

        "); + $this->assert_equal("hello\\'s

        world<\\/p>", + $string); + } + + public function clean_attribute_test() { + $safe_string = SafeString::of_safe_html("hello's

        world

        "); + $safe_string = html::clean_attribute($safe_string); + $this->assert_equal("hello's

        world

        ", + $safe_string); + } +} \ 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 a2d3d59b..8e5f8354 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -101,7 +101,7 @@ class Xss_Security_Test extends Unit_Test_Case { // 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->is_safe_html(true); $frame->expr_append("("); $token_number++; @@ -111,9 +111,11 @@ class Xss_Security_Test extends Unit_Test_Case { // 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")) && + in_array($tokens[$token_number + 2][1], array("of", "purify")) && self::_token_matches("(", $tokens, $token_number + 3)) { - $frame->is_safestring(true); + // Not checking for of_safe_html(). We want such calls to be marked dirty (thus reviewed). + + $frame->is_safe_html(true); $method = $tokens[$token_number + 2][1]; $frame->expr_append("::$method("); @@ -123,7 +125,7 @@ class Xss_Security_Test extends Unit_Test_Case { } } else if ($token[1] == "json_encode") { if (self::_token_matches("(", $tokens, $token_number + 1)) { - $frame->json_encode_called(true); + $frame->is_safe_js(true); $frame->expr_append("("); $token_number++; @@ -145,15 +147,34 @@ class Xss_Security_Test extends Unit_Test_Case { $token_number += 3; $token = $tokens[$token_number]; } + } else if ($token[1] == "html") { + 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("clean", "purify", "escape_for_js", "clean_attribute_test")) && + self::_token_matches("(", $tokens, $token_number + 3)) { + // Not checking for mark_safe(). We want such calls to be marked dirty (thus reviewed). + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); + + $token_number += 3; + $token = $tokens[$token_number]; + + if ("escape_for_js" == $method) { + $frame->is_safe_js(true); + } else { + $frame->is_safe_html(true); + } + } } } 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")) && + array("for_js", "for_html", "purified_html", "for_html_attr")) && self::_token_matches("(", $tokens, $token_number + 2)) { - $method = $tokens[$token_number + 1][1]; $frame->expr_append("$method("); @@ -161,11 +182,9 @@ class Xss_Security_Test extends Unit_Test_Case { $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); + $frame->is_safe_js(true); + } else { + $frame->is_safe_html(true); } } } else if ($frame) { @@ -199,12 +218,11 @@ class Xss_Security_Test extends Unit_Test_Case { $state = "DIRTY"; if ($frame->in_script_block()) { $state = "DIRTY_JS"; - if ($frame->for_js_called() || $frame->json_encode_called()) { + if ($frame->is_safe_js()) { $state = "CLEAN"; } } else { - if ($frame->is_safe_html() || $frame->is_safestring() || - $frame->purified_html_called() || $frame->for_html_called()) { + if ($frame->is_safe_html()) { $state = "CLEAN"; } } @@ -255,12 +273,8 @@ class Xss_Security_Test extends Unit_Test_Case { 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 $_is_safe_html = false; + private $_is_safe_js = false; private $_line; function __construct($line_number, $in_script_block) { @@ -283,13 +297,6 @@ class Xss_Security_Test_Frame { 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 is_safe_html($new_val=NULL) { if ($new_val !== NULL) { $this->_is_safe_html = (bool) $new_val; @@ -297,32 +304,11 @@ class Xss_Security_Test_Frame { return $this->_is_safe_html; } - 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) { + function is_safe_js($new_val=NULL) { if ($new_val !== NULL) { - $this->_purified_html_called = (bool) $new_val; + $this->_is_safe_js = (bool) $new_val; } - return $this->_purified_html_called; + return $this->_is_safe_js; } function line() { -- cgit v1.2.3 From b9bd1681a3b1496c0f1bbe5e6254ab4fd0c9fe30 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 22:54:20 -0700 Subject: Update all code to use helper method html::clean(), html::purify(), ... instead of SafeString directly. --- modules/comment/controllers/comments.php | 8 ++++---- modules/comment/helpers/comment_rss.php | 8 ++++---- modules/comment/views/admin_block_recent_comments.html.php | 6 +++--- modules/comment/views/admin_comments.html.php | 10 +++++----- modules/comment/views/comment.html.php | 6 +++--- modules/comment/views/comment.mrss.php | 12 ++++++------ modules/comment/views/comments.html.php | 6 +++--- modules/digibug/controllers/digibug.php | 2 +- modules/exif/views/exif_dialog.html.php | 4 ++-- modules/g2_import/helpers/g2_import.php | 2 +- modules/gallery/controllers/admin_advanced_settings.php | 2 +- modules/gallery/controllers/quick.php | 10 +++++----- modules/gallery/helpers/MY_html.php | 4 ++-- modules/gallery/helpers/gallery_rss.php | 4 ++-- modules/gallery/helpers/gallery_task.php | 4 ++-- modules/gallery/tests/Html_Helper_Test.php | 4 ++-- modules/gallery/tests/Xss_Security_Test.php | 4 ++-- modules/gallery/views/admin_advanced_settings.html.php | 6 +++--- modules/gallery/views/admin_block_log_entries.html.php | 2 +- modules/gallery/views/admin_block_photo_stream.html.php | 4 ++-- modules/gallery/views/admin_languages.html.php | 4 ++-- modules/gallery/views/admin_maintenance.html.php | 4 ++-- modules/gallery/views/admin_maintenance_show_log.html.php | 2 +- modules/gallery/views/move_tree.html.php | 8 ++++---- modules/gallery/views/permissions_browse.html.php | 4 ++-- modules/gallery/views/permissions_form.html.php | 2 +- modules/gallery/views/simple_uploader.html.php | 14 +++++++------- modules/info/views/info_block.html.php | 10 +++++----- modules/notification/views/comment_published.html.php | 12 ++++++------ modules/notification/views/item_added.html.php | 8 ++++---- modules/notification/views/item_deleted.html.php | 6 +++--- modules/notification/views/item_updated.html.php | 12 ++++++------ modules/organize/views/organize_dialog.html.php | 2 +- modules/organize/views/organize_tree.html.php | 6 +++--- modules/rss/views/feed.mrss.php | 14 +++++++------- modules/rss/views/rss_block.html.php | 2 +- modules/search/views/search.html.php | 6 +++--- modules/server_add/views/admin_server_add.html.php | 2 +- modules/server_add/views/server_add_tree.html.php | 4 ++-- modules/server_add/views/server_add_tree_dialog.html.php | 6 +++--- modules/tag/controllers/admin_tags.php | 2 +- modules/tag/views/admin_tags.html.php | 6 +++--- modules/tag/views/tag_cloud.html.php | 2 +- modules/user/controllers/logout.php | 2 +- modules/user/views/admin_users.html.php | 8 ++++---- modules/user/views/admin_users_group.html.php | 4 ++-- modules/user/views/login.html.php | 2 +- themes/default/views/album.html.php | 6 +++--- themes/default/views/dynamic.html.php | 4 ++-- themes/default/views/header.html.php | 4 ++-- themes/default/views/movie.html.php | 4 ++-- themes/default/views/photo.html.php | 6 +++--- 52 files changed, 143 insertions(+), 143 deletions(-) (limited to 'modules') diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php index 87633f4c..82b12893 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" => SafeString::of($comment->author_name()), + "author_name" => html::clean($comment->author_name()), "created" => $comment->created, - "text" => nl2br(SafeString::purify($comment->text))); + "text" => nl2br(html::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" => SafeString::of($comment->author_name()), + "author_name" => html::clean($comment->author_name()), "created" => $comment->created, - "text" => nl2br(SafeString::purify($comment->text))))); + "text" => nl2br(html::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 4151dcd0..b539887b 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" => SafeString::purify($item->title))); + t("Comments on %title", array("title" => html::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(SafeString::purify($comment->text)), + "text" => nl2br(html::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" => SafeString::purify($item->title), - "author" => SafeString::of($comment->author_name())), + "title" => html::purify($item->title), + "author" => html::clean($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 2c7a5cf1..dc3975e0 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 @@
      • "> " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="32" height="32" /> created) ?> %author_name said %comment_text', - array("author_name" => SafeString::of($comment->author_name()), - "comment_text" => text::limit_words(nl2br(SafeString::purify($comment->text)), 50))); ?> + array("author_name" => html::clean($comment->author_name()), + "comment_text" => text::limit_words(nl2br(html::purify($comment->text)), 50))); ?>
      diff --git a/modules/comment/views/admin_comments.html.php b/modules/comment/views/admin_comments.html.php index 8b0b4c29..801ce2b3 100644 --- a/modules/comment/views/admin_comments.html.php +++ b/modules/comment/views/admin_comments.html.php @@ -108,12 +108,12 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> -

      author_name()) ?>

      +

      author_name()) ?>

    • created) ?>

      - text)) ?> + text)) ?>
        diff --git a/modules/comment/views/comment.html.php b/modules/comment/views/comment.html.php index 31bb7f4d..1d0786cb 100644 --- a/modules/comment/views/comment.html.php +++ b/modules/comment/views/comment.html.php @@ -4,15 +4,15 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> gallery::date_time($comment->created), - "author_name" => SafeString::of($comment->author_name()))) ?> + "author_name" => html::clean($comment->author_name()))) ?>

        - text)) ?> + text)) ?>
        diff --git a/modules/comment/views/comment.mrss.php b/modules/comment/views/comment.mrss.php index ae7762d9..c2a4b538 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"> Gallery 3 - <?= SafeString::of($feed->title) ?> + <?= html::clean($feed->title) ?> uri ?> - description) ?> + description) ?> en-us @@ -22,14 +22,14 @@ children as $child): ?> - <?= SafeString::purify($child->title) ?> - item_uri) ?> - author) ?> + <?= html::purify($child->title) ?> + item_uri) ?> + author) ?> item_uri ?> pub_date ?> text)) ?>

        +

        text)) ?>

        diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index 9eac0502..1e45c946 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -18,16 +18,16 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> %name said', array("date" => date("Y-M-d H:i:s", $comment->created), - "name" => SafeString::of($comment->author_name()))); ?> + "name" => html::clean($comment->author_name()))); ?>

        - text)) ?> + text)) ?>
        diff --git a/modules/digibug/controllers/digibug.php b/modules/digibug/controllers/digibug.php index 509a8b70..0939704b 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" => SafeString::purify($item->title)); + "title_1" => html::purify($item->title)); print $v; } diff --git a/modules/exif/views/exif_dialog.html.php b/modules/exif/views/exif_dialog.html.php index a981ca09..11d1e212 100644 --- a/modules/exif/views/exif_dialog.html.php +++ b/modules/exif/views/exif_dialog.html.php @@ -14,14 +14,14 @@ - + - + diff --git a/modules/g2_import/helpers/g2_import.php b/modules/g2_import/helpers/g2_import.php index a01ca1db..7e5c6f75 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(SafeString::purify($comment->text)), 50))); + "comment" => text::limit_words(nl2br(html::purify($comment->text)), 50))); } /** diff --git a/modules/gallery/controllers/admin_advanced_settings.php b/modules/gallery/controllers/admin_advanced_settings.php index d727b654..43c77340 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" => SafeString::of($var_name), "module_name" => $module_name))); + array("var" => html::clean($var_name), "module_name" => $module_name))); print json_encode(array("result" => "success")); } diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index 8fddb563..20731f9c 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 %title this album's cover", array("title" => SafeString::purify($item->title))); + $msg = t("Made %title this album's cover", array("title" => html::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 %title? All photos and movies in the album will also be deleted.", - array("title" => SafeString::purify($item->title))); + array("title" => html::purify($item->title))); } else { print t("Are you sure you want to delete %title?", - array("title" => SafeString::purify($item->title))); + array("title" => html::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 %title", array("title" => SafeString::purify($item->title))); + $msg = t("Deleted album %title", array("title" => html::purify($item->title))); } else { - $msg = t("Deleted photo %title", array("title" => SafeString::purify($item->title))); + $msg = t("Deleted photo %title", array("title" => html::purify($item->title))); } $parent = $item->parent(); diff --git a/modules/gallery/helpers/MY_html.php b/modules/gallery/helpers/MY_html.php index eb388811..75114898 100644 --- a/modules/gallery/helpers/MY_html.php +++ b/modules/gallery/helpers/MY_html.php @@ -65,11 +65,11 @@ class html extends html_Core { * * Example:
            *   
         
        -

        SafeString::purify($album->title))) ?>

        +

        html::purify($album->title))) ?>

        diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 387d5977..5b676889 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -5,7 +5,7 @@ - title) ?> + title) ?>
          @@ -17,7 +17,7 @@ " ref="id ?>"> - title) ?> + title) ?> id == $album->id): ?> @@ -29,7 +29,7 @@ - title) ?> + title) ?> diff --git a/modules/rss/views/feed.mrss.php b/modules/rss/views/feed.mrss.php index 7298b7f4..731703c7 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"> gallery3 - <?= SafeString::of($feed->title) ?> + <?= html::clean($feed->title) ?> uri ?> - description) ?> + description) ?> en-us @@ -22,25 +22,25 @@ children as $child): ?> - <?= SafeString::of($child->title) ?> + <?= html::clean($child->title) ?> type}s/{$child->id}") ?> type}s/{$child->id}") ?> created); ?> description) ?> + description) ?>

          type == "photo" || $child->type == "album"): ?>
          type}s/{$child->id}") ?>">
          - description) ?> + description) ?>

          ]]>
          diff --git a/modules/rss/views/rss_block.html.php b/modules/rss/views/rss_block.html.php index cd8db89d..737731b6 100644 --- a/modules/rss/views/rss_block.html.php +++ b/modules/rss/views/rss_block.html.php @@ -5,7 +5,7 @@ - + diff --git a/modules/search/views/search.html.php b/modules/search/views/search.html.php index e5c7b4a6..7963948d 100644 --- a/modules/search/views/search.html.php +++ b/modules/search/views/search.html.php @@ -8,7 +8,7 @@
          • - +
          • for_html_attr() ?>" /> @@ -31,10 +31,10 @@ id") ?>"> thumb_img() ?>

            - title) ?> + title) ?>

            - description)) ?> + description)) ?>
          • diff --git a/modules/server_add/views/admin_server_add.html.php b/modules/server_add/views/admin_server_add.html.php index c4439bda..b48a19da 100644 --- a/modules/server_add/views/admin_server_add.html.php +++ b/modules/server_add/views/admin_server_add.html.php @@ -16,7 +16,7 @@ class="gRemoveDir ui-icon ui-icon-trash"> X - +
          diff --git a/modules/server_add/views/server_add_tree.html.php b/modules/server_add/views/server_add_tree.html.php index 2f65a590..dbae42c5 100644 --- a/modules/server_add/views/server_add_tree.html.php +++ b/modules/server_add/views/server_add_tree.html.php @@ -10,7 +10,7 @@
        • - +
            @@ -24,7 +24,7 @@ file=" '\\"')) ?>" > - + 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 912e69b6..8eb6e4df 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 @@
            -

            SafeString::purify($item->title))) ?>

            +

            html::purify($item->title))) ?>

              parents() as $parent): ?>
            • - title) ?> + title) ?>
            • - title) ?> + title) ?>
            diff --git a/modules/tag/controllers/admin_tags.php b/modules/tag/controllers/admin_tags.php index f1b4ca3a..8b8dde21 100644 --- a/modules/tag/controllers/admin_tags.php +++ b/modules/tag/controllers/admin_tags.php @@ -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" => SafeString::of($tag->name))); + "new_tagname" => html::clean($tag->name))); } else { print json_encode( array("result" => "error", diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php index 30dd0728..3d805c5e 100644 --- a/modules/tag/views/admin_tags.html.php +++ b/modules/tag/views/admin_tags.html.php @@ -32,7 +32,7 @@ name, 0, 1)) ?> - +
              $tags_per_column): /* new column */ ?> @@ -42,12 +42,12 @@
            - + diff --git a/modules/user/controllers/logout.php b/modules/user/controllers/logout.php index 4b141a1c..fc3ced56 100644 --- a/modules/user/controllers/logout.php +++ b/modules/user/controllers/logout.php @@ -24,7 +24,7 @@ class Logout_Controller extends Controller { $user = user::active(); user::logout(); log::info("user", t("User %name logged out", array("name" => $user->name)), - html::anchor("user/$user->id", SafeString::of($user->name))); + html::anchor("user/$user->id", html::clean($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/views/admin_users.html.php b/modules/user/views/admin_users.html.php index 36c4f4fd..9455f9d9 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -68,16 +68,16 @@ " title="" - alt="name) ?>" + alt="name) ?>" width="20" height="20" /> - name) ?> + name) ?> - full_name) ?> + full_name) ?> - email) ?> + email) ?> 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 f89a4392..8418ebc9 100644 --- a/modules/user/views/admin_users_group.html.php +++ b/modules/user/views/admin_users_group.html.php @@ -1,6 +1,6 @@

            - name) ?> + name) ?> special): ?> id") ?>" title=" $group->name)) ?>" @@ -17,7 +17,7 @@

              @@ -16,7 +16,7 @@ width="thumb_width ?>" height="thumb_height ?>" /> -

              title) ?>

              +

              title) ?>

              thumb_bottom($child) ?> diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 237743b7..910814dd 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -28,8 +28,8 @@ movie_img(array("class" => "gMovie", "id" => "gMovieId-{$item->id}")) ?>
              -

              title) ?>

              -
              description)) ?>
              +

              title) ?>

              +
              description)) ?>
              photo_bottom() ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 5b5cb12b..c601c4cc 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ *
        */ - static function clean_js($string) { + static function js_string($string) { return SafeString::of($string)->for_js(); } diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 9614a213..0767a665 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -92,17 +92,17 @@ class SafeString_Core { } /** - * Safe for use in JavaScript. + * Safe for use as JavaScript string. * * Example:
            *   
            * 
        * @return the string escaped for use in JavaScript. */ function for_js() { - return self::_escape_for_js($this->_raw_string); + return json_encode((string) $this->_raw_string); } /** @@ -152,14 +152,6 @@ class SafeString_Core { 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)) { diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php index a9903256..f5ce7fa4 100644 --- a/modules/gallery/tests/Html_Helper_Test.php +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -40,9 +40,9 @@ class Html_Helper_Test extends Unit_Test_Case { $safe_string_2); } - public function clean_js_test() { - $string = html::clean_js("hello's

        world

        "); - $this->assert_equal("hello\\'s

        world<\\/p>", + public function js_string_test() { + $string = html::js_string("hello's

        world

        "); + $this->assert_equal('"hello\'s

        world<\\/p>"', $string); } diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 0fc7f6f3..ede55240 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -49,7 +49,7 @@ class SafeString_Test extends Unit_Test_Case { public function for_js_test() { $safe_string = new SafeString('"Foo\'s bar"'); $js_string = $safe_string->for_js(); - $this->assert_equal('\\"Foo<\\/em>\\\'s bar\\"', + $this->assert_equal('"\\"Foo<\\/em>\'s bar\\""', $js_string); } @@ -96,21 +96,21 @@ class SafeString_Test extends Unit_Test_Case { public function of_fluid_api_test() { $escaped_string = SafeString::of("Foo's bar")->for_js(); - $this->assert_equal("Foo\\'s bar", $escaped_string); + $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

        world

        "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

        world

        ", $safe_string_2); - $this->assert_equal("hello\\'s

        world<\\/p>", $safe_string_2->for_js()); + $this->assert_equal('"hello\'s

        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

        world

        "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

        world

        ", $safe_string_2); - $this->assert_equal("hello\\'s

        world<\\/p>", $safe_string_2->for_js()); + $this->assert_equal('"hello\'s

        world<\\/p>"', $safe_string_2->for_js()); } public function safestring_of_safestring_safe_status_override_test() { diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index b385580d..3a22afc1 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -188,7 +188,7 @@ class Xss_Security_Test extends Unit_Test_Case { 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("clean", "purify", "clean_js", "clean_attribute")) && + array("clean", "purify", "js_string", "clean_attribute")) && self::_token_matches("(", $tokens, $token_number + 3)) { // Not checking for mark_safe(). We want such calls to be marked dirty (thus reviewed). @@ -198,7 +198,7 @@ class Xss_Security_Test extends Unit_Test_Case { $token_number += 3; $token = $tokens[$token_number]; - if ("clean_js" == $method) { + if ("js_string" == $method) { $frame->is_safe_js(true); } else { $frame->is_safe_html(true); -- cgit v1.2.3 From 00c73ec852c29c214d72193ce368bc12a7305794 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sun, 30 Aug 2009 15:34:46 -0700 Subject: Updating uses of html::js_string and SafeString::for_js (value now contains string delimiters) --- modules/gallery/views/admin_languages.html.php | 86 +++++++++++------------ modules/gallery/views/l10n_client.html.php | 10 +-- modules/gallery/views/permissions_browse.html.php | 17 ++--- modules/gallery/views/simple_uploader.html.php | 50 ++++++------- themes/admin_default/views/admin.html.php | 2 +- themes/default/views/page.html.php | 4 +- themes/default/views/photo.html.php | 2 +- 7 files changed, 85 insertions(+), 86 deletions(-) (limited to 'modules') diff --git a/modules/gallery/views/admin_languages.html.php b/modules/gallery/views/admin_languages.html.php index ae2b3383..fa97d299 100644 --- a/modules/gallery/views/admin_languages.html.php +++ b/modules/gallery/views/admin_languages.html.php @@ -11,12 +11,11 @@ - + $display_name): ?> - - + @@ -24,24 +23,24 @@ - + "> - - + + - +
        - - + +
        - for_html_attr() ?>" /> + for_html_attr() ?>" /> - - diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php index d9395b3f..231daa04 100644 --- a/modules/gallery/views/permissions_browse.html.php +++ b/modules/gallery/views/permissions_browse.html.php @@ -5,9 +5,9 @@ $.ajax({ url: form_url.replace("__ITEM__", id), success: function(data) { - $("#gEditPermissionForm").html(data); - $(".active").removeClass("active"); - $("#item-" + id).addClass("active"); + $("#gEditPermissionForm").html(data); + $(".active").removeClass("active"); + $("#item-" + id).addClass("active"); } }); } @@ -28,13 +28,14 @@

        • - mod_rewrite and set AllowOverride FileInfo Options to fix this.", array("mod_rewrite_attrs" => "href=\"http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html\" target=\"_blank\"", "apache_attrs" => "href=\"http://httpd.apache.org/docs/2.0/mod/core.html#allowoverride\" target=\"_blank\"")) ?> + mod_rewrite and set AllowOverride FileInfo Options to fix this.", + array("mod_rewrite_attrs" => html::mark_safe("href=\"http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html\" target=\"_blank\"", "apache_attrs" => "href=\"http://httpd.apache.org/docs/2.0/mod/core.html#allowoverride\" target=\"_blank\""))) ?>
        - +

        - + - +
        diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index ccb166fc..9cf554ec 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -82,22 +82,22 @@ diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index 2ed8c38e..3b1ff92c 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -23,7 +23,7 @@ script("gallery.common.js") ?> script("gallery.ajax.js") ?> script("gallery.dialog.js") ?> diff --git a/themes/default/views/page.html.php b/themes/default/views/page.html.php index 844ef295..2696442b 100644 --- a/themes/default/views/page.html.php +++ b/themes/default/views/page.html.php @@ -12,7 +12,7 @@ item()->is_album()): ?> $theme->item()->title)) ?> item()->is_photo()): ?> - $theme->item()->title)) ?> + $theme->item()->title)) ?> $theme->item()->title)) ?> @@ -51,7 +51,7 @@ script("gallery.common.js") ?> script("gallery.ajax.js") ?> script("gallery.dialog.js") ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 00e157ce..5289b467 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ 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 "expr_append($inline_html); - } - - // Note: This approach won't catch }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('{]*>}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); + $token = $tokens[$token_number]; + + // Are we in a 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 "expr_append($inline_html); + } + + // Note: This approach won't catch }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('{]*>}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; + // Store the < ? = ... ? > block that just ended here. + $found[$view][] = $frame; + $frame = null; } else if ($frame && $token[0] == T_VARIABLE) { - $frame->expr_append($token[1]); + $frame->expr_append($token[1]); if ($token[1] == '$theme') { - if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], - array("thumb_proportion", "site_menu", "album_menu", "tag_menu", "photo_menu", + if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("thumb_proportion", "site_menu", "album_menu", "tag_menu", "photo_menu", "context_menu", "pager", "site_status", "messages", "album_blocks", "album_bottom", "album_top", "body_attributes", "credits", "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")) && - self::_token_matches("(", $tokens, $token_number + 3)) { + self::_token_matches("(", $tokens, $token_number + 3)) { - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("->$method("); + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("->$method("); - $token_number += 3; - $token = $tokens[$token_number]; + $token_number += 3; + $token = $tokens[$token_number]; $frame->is_safe_html(true); - } else if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], - array("css", "script", "url")) && - self::_token_matches("(", $tokens, $token_number + 3) && - // Only allow constant strings here - self::_token_matches(array(T_CONSTANT_ENCAPSED_STRING), $tokens, $token_number + 4)) { + } else if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("css", "script", "url")) && + self::_token_matches("(", $tokens, $token_number + 3) && + // Only allow constant strings here + self::_token_matches(array(T_CONSTANT_ENCAPSED_STRING), $tokens, $token_number + 4)) { - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("->$method("); + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("->$method("); - $token_number += 4; - $token = $tokens[$token_number]; + $token_number += 4; + $token = $tokens[$token_number]; $frame->is_safe_html(true); - } + } } - } 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_safe_html(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", "purify")) && - self::_token_matches("(", $tokens, $token_number + 3)) { + } 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_safe_html(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", "purify")) && + self::_token_matches("(", $tokens, $token_number + 3)) { // Not checking for of_safe_html(). We want such calls to be marked dirty (thus reviewed). - $frame->is_safe_html(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->is_safe_js(true); - $frame->expr_append("("); - - $token_number++; - $token = $tokens[$token_number]; - } - } else if ($token[1] == "url") { - // url methods return safe HTML - 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_safe_html(true); - - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("::$method("); - - $token_number += 3; - $token = $tokens[$token_number]; - } - } else if ($token[1] == "html") { - 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("clean", "purify", "js_string", "clean_attribute")) && - self::_token_matches("(", $tokens, $token_number + 3)) { + $frame->is_safe_html(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->is_safe_js(true); + $frame->expr_append("("); + + $token_number++; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "url") { + // url methods return safe HTML + 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_safe_html(true); + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); + + $token_number += 3; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "html") { + 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("clean", "purify", "js_string", "clean_attribute")) && + self::_token_matches("(", $tokens, $token_number + 3)) { // Not checking for mark_safe(). We want such calls to be marked dirty (thus reviewed). - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("::$method("); + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); - $token_number += 3; - $token = $tokens[$token_number]; + $token_number += 3; + $token = $tokens[$token_number]; if ("js_string" == $method) { $frame->is_safe_js(true); } else { $frame->is_safe_html(true); } - } - } - } 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", "for_html_attr")) && - 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->is_safe_js(true); - } else { - $frame->is_safe_html(true); - } - } + } + } + } 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", "for_html_attr")) && + 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->is_safe_js(true); + } else { + $frame->is_safe_html(true); + } + } } else if ($frame) { - $frame->expr_append($token[1]); - } + $frame->expr_append($token[1]); + } } } @@ -252,26 +252,26 @@ class Xss_Security_Test extends Unit_Test_Case { ksort($found); foreach ($found as $view => $frames) { foreach ($frames as $frame) { - $state = "DIRTY"; - if ($frame->in_script_block()) { - $state = "DIRTY_JS"; - if ($frame->is_safe_js()) { - $state = "CLEAN"; - } - } else { - if ($frame->is_safe_html()) { - $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()); + $state = "DIRTY"; + if ($frame->in_script_block()) { + $state = "DIRTY_JS"; + if ($frame->is_safe_js()) { + $state = "CLEAN"; + } + } else { + if ($frame->is_safe_html()) { + $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); @@ -280,7 +280,7 @@ class Xss_Security_Test extends Unit_Test_Case { $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) ); + $return_value, "XSS golden file mismatch. Output:\n" . implode("\n", $output) ); } private static function _create_frame($token, $in_script_block) { @@ -296,9 +296,9 @@ class Xss_Security_Test extends Unit_Test_Case { if (is_array($expected_token)) { for ($i = 0; $i < count($expected_token); $i++) { - if ($expected_token[$i] != $token[$i]) { - return false; - } + if ($expected_token[$i] != $token[$i]) { + return false; + } } return true; } else { diff --git a/modules/server_add/helpers/server_add_event.php b/modules/server_add/helpers/server_add_event.php index 6b21ec2e..b2d55153 100644 --- a/modules/server_add/helpers/server_add_event.php +++ b/modules/server_add/helpers/server_add_event.php @@ -35,7 +35,7 @@ class server_add_event_Core { // turn that into a dropdown if there are two different ways to add things. Do that in a // portable way for now. If we find ourselves duplicating this pattern, we should make an // API method for this. - $add_menu = $menu->get("add_menu"); + $add_menu = $menu->get("add_menu"); $add_menu->append(Menu::factory("dialog") ->id("server_add") ->label(t("Server add")) -- cgit v1.2.3 From 3aef420d485871ed95be742bae0d971e637e4a75 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sun, 30 Aug 2009 18:37:01 -0700 Subject: Updating XSS golden file --- modules/gallery/tests/xss_data.txt | 73 ++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 38 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index de37d11e..5b43d1e5 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -61,12 +61,12 @@ modules/gallery/views/admin_graphics_imagemagick.html.php 2 DIRTY $is_ac modules/gallery/views/admin_graphics_imagemagick.html.php 2 DIRTY $tk->installed?" gInstalledToolkit":" gUnavailable" modules/gallery/views/admin_graphics_imagemagick.html.php 18 DIRTY $tk->error modules/gallery/views/admin_languages.html.php 9 DIRTY access::csrf_form_field() -modules/gallery/views/admin_languages.html.php 28 DIRTY (isset($installed_locales[$code]))?"installed":"" -modules/gallery/views/admin_languages.html.php 28 DIRTY ($default_locale==$code)?" default":"" -modules/gallery/views/admin_languages.html.php 29 DIRTY form::checkbox("installed_locales[]",$code,isset($installed_locales[$code])) -modules/gallery/views/admin_languages.html.php 30 DIRTY $display_name -modules/gallery/views/admin_languages.html.php 32 DIRTY form::radio("default_locale",$code,($default_locale==$code),((isset($installed_locales[$code]))?'':'disabled="disabled"')) -modules/gallery/views/admin_languages.html.php 104 DIRTY $share_translations_form +modules/gallery/views/admin_languages.html.php 27 DIRTY (isset($installed_locales[$code]))?"installed":"" +modules/gallery/views/admin_languages.html.php 27 DIRTY ($default_locale==$code)?" default":"" +modules/gallery/views/admin_languages.html.php 28 DIRTY form::checkbox("installed_locales[]",$code,isset($installed_locales[$code])) +modules/gallery/views/admin_languages.html.php 29 DIRTY $display_name +modules/gallery/views/admin_languages.html.php 31 DIRTY form::radio("default_locale",$code,($default_locale==$code),((isset($installed_locales[$code]))?'':'disabled="disabled"')) +modules/gallery/views/admin_languages.html.php 102 DIRTY $share_translations_form modules/gallery/views/admin_maintenance.html.php 24 DIRTY log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 24 DIRTY ($i%2==0)?"gOddRow":"gEvenRow" modules/gallery/views/admin_maintenance.html.php 26 DIRTY $task->name @@ -105,20 +105,20 @@ modules/gallery/views/admin_themes_preview.html.php 7 DIRTY $url modules/gallery/views/kohana_error_page.php 102 DIRTY $message modules/gallery/views/kohana_error_page.php 116 DIRTY $trace modules/gallery/views/kohana_profiler.php 32 DIRTY $profile->render(); -modules/gallery/views/l10n_client.html.php 20 DIRTY $string["translation"]===""?"untranslated":"translated" -modules/gallery/views/l10n_client.html.php 22 DIRTY $string["source"]["one"] -modules/gallery/views/l10n_client.html.php 23 DIRTY $string["source"]["other"] -modules/gallery/views/l10n_client.html.php 25 DIRTY $string["source"] -modules/gallery/views/l10n_client.html.php 31 DIRTY $l10n_search_form -modules/gallery/views/l10n_client.html.php 40 DIRTY access::csrf_form_field() -modules/gallery/views/l10n_client.html.php 41 DIRTY form::hidden("l10n-message-key") -modules/gallery/views/l10n_client.html.php 42 DIRTY form::textarea("l10n-edit-translation","",' rows="5" class="translationField"') -modules/gallery/views/l10n_client.html.php 45 DIRTY form::textarea("l10n-edit-plural-translation-zero","",' rows="2"') -modules/gallery/views/l10n_client.html.php 49 DIRTY form::textarea("l10n-edit-plural-translation-one","",' rows="2"') -modules/gallery/views/l10n_client.html.php 53 DIRTY form::textarea("l10n-edit-plural-translation-two","",' rows="2"') -modules/gallery/views/l10n_client.html.php 57 DIRTY form::textarea("l10n-edit-plural-translation-few","",' rows="2"') -modules/gallery/views/l10n_client.html.php 61 DIRTY form::textarea("l10n-edit-plural-translation-many","",' rows="2"') -modules/gallery/views/l10n_client.html.php 66 DIRTY form::textarea("l10n-edit-plural-translation-other","",' rows="2"') +modules/gallery/views/l10n_client.html.php 21 DIRTY $string["translation"]===""?"untranslated":"translated" +modules/gallery/views/l10n_client.html.php 23 DIRTY $string["source"]["one"] +modules/gallery/views/l10n_client.html.php 24 DIRTY $string["source"]["other"] +modules/gallery/views/l10n_client.html.php 26 DIRTY $string["source"] +modules/gallery/views/l10n_client.html.php 32 DIRTY $l10n_search_form +modules/gallery/views/l10n_client.html.php 41 DIRTY access::csrf_form_field() +modules/gallery/views/l10n_client.html.php 42 DIRTY form::hidden("l10n-message-key") +modules/gallery/views/l10n_client.html.php 43 DIRTY form::textarea("l10n-edit-translation","",' rows="5" class="translationField"') +modules/gallery/views/l10n_client.html.php 46 DIRTY form::textarea("l10n-edit-plural-translation-zero","",' rows="2"') +modules/gallery/views/l10n_client.html.php 50 DIRTY form::textarea("l10n-edit-plural-translation-one","",' rows="2"') +modules/gallery/views/l10n_client.html.php 54 DIRTY form::textarea("l10n-edit-plural-translation-two","",' rows="2"') +modules/gallery/views/l10n_client.html.php 58 DIRTY form::textarea("l10n-edit-plural-translation-few","",' rows="2"') +modules/gallery/views/l10n_client.html.php 62 DIRTY form::textarea("l10n-edit-plural-translation-many","",' rows="2"') +modules/gallery/views/l10n_client.html.php 67 DIRTY form::textarea("l10n-edit-plural-translation-other","",' rows="2"') modules/gallery/views/maintenance.html.php 46 DIRTY user::get_login_form("login/auth_html") modules/gallery/views/move_browse.html.php 39 DIRTY $tree modules/gallery/views/move_browse.html.php 43 DIRTY access::csrf_form_field() @@ -132,11 +132,11 @@ modules/gallery/views/move_tree.html.php 13 DIRTY $child modules/gallery/views/move_tree.html.php 15 DIRTY $child->id modules/gallery/views/movieplayer.html.php 2 DIRTY html::anchor($item->file_url(true),"",$attrs) modules/gallery/views/movieplayer.html.php 5 DIRTY $attrs["id"] -modules/gallery/views/permissions_browse.html.php 40 DIRTY $parent->id modules/gallery/views/permissions_browse.html.php 41 DIRTY $parent->id -modules/gallery/views/permissions_browse.html.php 46 DIRTY $item->id +modules/gallery/views/permissions_browse.html.php 42 DIRTY $parent->id modules/gallery/views/permissions_browse.html.php 47 DIRTY $item->id -modules/gallery/views/permissions_browse.html.php 54 DIRTY $form +modules/gallery/views/permissions_browse.html.php 48 DIRTY $item->id +modules/gallery/views/permissions_browse.html.php 55 DIRTY $form modules/gallery/views/permissions_form.html.php 24 DIRTY $lock->id modules/gallery/views/permissions_form.html.php 32 DIRTY $group->id modules/gallery/views/permissions_form.html.php 32 DIRTY $permission->id @@ -178,25 +178,22 @@ modules/notification/views/item_deleted.html.php 18 DIRTY $item- modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->url(array(),true) modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(),true) modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(),true) -modules/organize/views/organize_dialog.html.php 21 DIRTY $album_tree -modules/organize/views/organize_dialog.html.php 28 DIRTY $micro_thumb_grid -modules/organize/views/organize_dialog.html.php 36 DIRTY form::dropdown(array("id"=>"gOrganizeSortColumn"),album::get_sort_order_options(),$album->sort_column) -modules/organize/views/organize_dialog.html.php 37 DIRTY form::dropdown(array("id"=>"gOrganizeSortOrder"),array("ASC"=>"Ascending","DESC"=>"Descending"),$album->sort_order) +modules/organize/views/organize_dialog.html.php 22 DIRTY $album_tree +modules/organize/views/organize_dialog.html.php 29 DIRTY $micro_thumb_grid +modules/organize/views/organize_dialog.html.php 37 DIRTY form::dropdown(array("id"=>"gOrganizeSortColumn"),album::get_sort_order_options(),$album->sort_column) +modules/organize/views/organize_dialog.html.php 38 DIRTY form::dropdown(array("id"=>"gOrganizeSortOrder"),array("ASC"=>"Ascending","DESC"=>"Descending"),$album->sort_order) modules/organize/views/organize_thumb_grid.html.php 3 DIRTY $child->id modules/organize/views/organize_thumb_grid.html.php 4 DIRTY $child->id modules/organize/views/organize_thumb_grid.html.php 5 DIRTY $child->is_album()?"gAlbum":"gPhoto" modules/organize/views/organize_thumb_grid.html.php 6 DIRTY $child->thumb_img(array("class"=>"gThumbnail","ref"=>$child->id),90,true) -modules/organize/views/organize_tree.html.php 3 DIRTY access::can("edit",$parent)?"":"gViewOnly" -modules/organize/views/organize_tree.html.php 4 DIRTY $parent->id -modules/organize/views/organize_tree.html.php 7 DIRTY $parent->id -modules/organize/views/organize_tree.html.php 14 DIRTY access::can("edit",$peer)?"":"gViewOnly" -modules/organize/views/organize_tree.html.php 15 DIRTY $peer->id -modules/organize/views/organize_tree.html.php 16 DIRTY $peer->id==$album->id?"ui-icon-minus":"ui-icon-plus" -modules/organize/views/organize_tree.html.php 18 DIRTY $peer->id==$album->id?"selected":"" -modules/organize/views/organize_tree.html.php 19 DIRTY $peer->id -modules/organize/views/organize_tree.html.php 26 DIRTY access::can("edit",$child)?"":"gViewOnly" -modules/organize/views/organize_tree.html.php 27 DIRTY $child->id -modules/organize/views/organize_tree.html.php 31 DIRTY $child->id +modules/organize/views/organize_tree.html.php 2 DIRTY access::can("edit",$album)?"":"gViewOnly" +modules/organize/views/organize_tree.html.php 3 DIRTY $album->id +modules/organize/views/organize_tree.html.php 7 DIRTY $selected&&$album->id==$selected->id?"selected":"" +modules/organize/views/organize_tree.html.php 9 DIRTY $album->id +modules/organize/views/organize_tree.html.php 15 DIRTY View::factory("organize_tree.html",array("selected"=>$selected,"album"=>$child)); +modules/organize/views/organize_tree.html.php 17 DIRTY access::can("edit",$child)?"":"gViewOnly" +modules/organize/views/organize_tree.html.php 18 DIRTY $child->id +modules/organize/views/organize_tree.html.php 21 DIRTY $child->id modules/recaptcha/views/admin_recaptcha.html.php 10 DIRTY $form modules/recaptcha/views/admin_recaptcha.html.php 23 DIRTY $public_key modules/recaptcha/views/form_recaptcha.html.php 7 DIRTY $public_key -- cgit v1.2.3 From 0a0c7a78e6333728bad19611cccb095241545cc6 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sun, 30 Aug 2009 21:25:21 -0700 Subject: Check for href="" (malicious "javascript:..." string) --- modules/gallery/tests/Xss_Security_Test.php | 47 +++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 6c141c52..ef36f6b7 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -32,6 +32,7 @@ class Xss_Security_Test extends Unit_Test_Case { $frame = null; $script_block = 0; $in_script_block = false; + $inline_html = ""; for ($token_number = 0; $token_number < count($tokens); $token_number++) { $token = $tokens[$token_number]; @@ -81,6 +82,8 @@ class Xss_Security_Test extends Unit_Test_Case { } } + $href_attribute_start = preg_match('{href\s*=\s*[\'"]?\s*$}i', str_replace("\n", "", $inline_html)); + // Look and report each instance of < ? = ... ? > if (!is_array($token)) { // A single char token, e.g: ; ( ) @@ -89,7 +92,8 @@ class Xss_Security_Test extends Unit_Test_Case { } } 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); + $frame = self::_create_frame($token, $in_script_block, $href_attribute_start); + $href_attribute_start = false; } else if ($frame && $token[0] == T_CLOSE_TAG) { // Store the < ? = ... ? > block that just ended here. $found[$view][] = $frame; @@ -177,6 +181,7 @@ class Xss_Security_Test extends Unit_Test_Case { "abs_file", "merge")) && self::_token_matches("(", $tokens, $token_number + 3)) { $frame->is_safe_html(true); + $frame->is_safe_href_attr(true); $method = $tokens[$token_number + 2][1]; $frame->expr_append("::$method("); @@ -237,6 +242,8 @@ class Xss_Security_Test extends Unit_Test_Case { * DIRTY_JS: * In }i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { $last_match = array_pop($matches[0]); if (is_array($last_match)) { @@ -75,7 +76,7 @@ class Xss_Security_Test extends Unit_Test_Case { $closing_script_pos = $last_match; } } - if (preg_match('{]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + if (preg_match_all('{]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { $last_match = array_pop($matches[0]); if (is_array($last_match)) { $opening_script_pos = $last_match[1]; -- cgit v1.2.3 From d2cea7905e342c2a9a7cec03058ab762d0d1ba7f Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 00:53:17 -0700 Subject: Remove debugging code --- modules/gallery/tests/Xss_Security_Test.php | 1 - 1 file changed, 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 34ecc4fe..85624517 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -21,7 +21,6 @@ class Xss_Security_Test extends Unit_Test_Case { public function find_unescaped_variables_in_views_test() { $found = array(); foreach (glob("*/*/views/*.php") as $view) { - if ($view != "modules/tag/views/admin_tags.html.php") continue; // List of all tokens without whitespace, simplifying parsing. $tokens = array(); foreach (token_get_all(file_get_contents($view)) as $token) { -- cgit v1.2.3 From ff1979e12e0b012374e2ab3712b19f87e1a92e64 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:12:02 -0700 Subject: Fix XSS in tags JS --- modules/tag/js/tag.js | 10 ++++++++-- modules/tag/views/admin_tags.html.php | 8 ++++---- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'modules') diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 61ac73f4..aaae9e72 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -27,18 +27,24 @@ function closeEditInPlaceForms() { } } +function str_replace(search_term, replacement, string) { + var temp = string.split(search_term); + return temp.join(replacement); +} + function editInPlace(element) { closeEditInPlaceForms(); // create edit form var tag_id = $(this).attr('id').substr(5); - var tag_name = $(this).text(); + var tag_name = $(this).html(); var tag_width = $(this).width(); $(this).parent().data("revert", $(this).parent().html()); var form = '
        '; form += ''; - form += ''; + form += ''; form += ''; form += '' + cancel_i18n + ''; form += '
        '; diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php index 3d805c5e..8f3693aa 100644 --- a/modules/tag/views/admin_tags.html.php +++ b/modules/tag/views/admin_tags.html.php @@ -1,9 +1,9 @@

        -- cgit v1.2.3 From 94c201f265c758fad38eb69c0a5878970119197a Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:17:39 -0700 Subject: XSS escape in form helper and forge where missing. --- modules/forge/libraries/Form_Checkbox.php | 2 +- modules/forge/libraries/Form_Checklist.php | 2 +- modules/forge/libraries/Form_Group.php | 2 +- system/helpers/form.php | 19 +++++++++++++------ 4 files changed, 16 insertions(+), 9 deletions(-) (limited to 'modules') diff --git a/modules/forge/libraries/Form_Checkbox.php b/modules/forge/libraries/Form_Checkbox.php index b94fc438..aded4fdf 100644 --- a/modules/forge/libraries/Form_Checkbox.php +++ b/modules/forge/libraries/Form_Checkbox.php @@ -68,7 +68,7 @@ class Form_Checkbox_Core extends Form_Input { $label = ' '.ltrim($label); } - return ''; + return ''; } protected function load_value() diff --git a/modules/forge/libraries/Form_Checklist.php b/modules/forge/libraries/Form_Checklist.php index 99b455bd..4536d396 100644 --- a/modules/forge/libraries/Form_Checklist.php +++ b/modules/forge/libraries/Form_Checklist.php @@ -67,7 +67,7 @@ class Form_Checklist_Core extends Form_Input { $data['value'] = $val; $data['checked'] = $checked; - $checklist .= '
      • '.$nl; + $checklist .= '
      • '.$nl; } $checklist .= '

      '; diff --git a/modules/forge/libraries/Form_Group.php b/modules/forge/libraries/Form_Group.php index 29eff510..e0601321 100644 --- a/modules/forge/libraries/Form_Group.php +++ b/modules/forge/libraries/Form_Group.php @@ -57,7 +57,7 @@ class Form_Group_Core extends Forge { { if ($label = $this->data['label']) { - return $this->data['label']; + return html::purify($this->data['label']); } } else diff --git a/system/helpers/form.php b/system/helpers/form.php index ce8767c5..815eef84 100644 --- a/system/helpers/form.php +++ b/system/helpers/form.php @@ -283,15 +283,21 @@ class form_Core { // Inner key should always be a string $inner_key = (string) $inner_key; - $sel = in_array($inner_key, $selected) ? ' selected="selected"' : ''; - $input .= ''."\n"; + $attr = array('value' => $inner_key); + if (in_array($inner_key, $selected)) { + $attr['selected'] = 'selected'; + } + $input .= ''."\n"; } $input .= ''."\n"; } else { - $sel = in_array($key, $selected) ? ' selected="selected"' : ''; - $input .= ''."\n"; + $attr = array('value' => $key); + if (in_array($key, $selected)) { + $attr['selected'] = 'selected'; + } + $input .= ''."\n"; } } $input .= ''; @@ -410,8 +416,9 @@ class form_Core { { $value = arr::remove('value', $data); } + // $value must be ::purify - return ''.$value.''; + return ''.html::purify($value).''; } /** @@ -455,7 +462,7 @@ class form_Core { $text = ucwords(inflector::humanize($data['for'])); } - return ''.$text.''; + return ''.html::purify($text).''; } /** -- cgit v1.2.3 From 53711225ac9d116e72c159de943284fd55fe26e4 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:28:52 -0700 Subject: XSS / style fixes for newly detected issues (after fixing XSS scanner) --- modules/comment/views/admin_comments.html.php | 6 +++--- modules/gallery/views/admin_dashboard.html.php | 2 +- modules/gallery/views/admin_graphics.html.php | 2 +- modules/gallery/views/admin_maintenance_task.html.php | 2 +- modules/recaptcha/views/admin_recaptcha.html.php | 4 ++-- modules/recaptcha/views/form_recaptcha.html.php | 2 +- modules/user/views/login_ajax.html.php | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'modules') diff --git a/modules/comment/views/admin_comments.html.php b/modules/comment/views/admin_comments.html.php index f5970ae1..455cd714 100644 --- a/modules/comment/views/admin_comments.html.php +++ b/modules/comment/views/admin_comments.html.php @@ -1,7 +1,7 @@ diff --git a/modules/recaptcha/views/form_recaptcha.html.php b/modules/recaptcha/views/form_recaptcha.html.php index d4031586..4ec04c49 100644 --- a/modules/recaptcha/views/form_recaptcha.html.php +++ b/modules/recaptcha/views/form_recaptcha.html.php @@ -8,7 +8,7 @@ "gRecaptcha", { theme: "white", - custom_translations : { instructions_visual : ""}, + custom_translations : { instructions_visual : for_js() ?>}, callback: Recaptcha.focus_response_field } ); diff --git a/modules/user/views/login_ajax.html.php b/modules/user/views/login_ajax.html.php index d697c958..56bc1cbd 100644 --- a/modules/user/views/login_ajax.html.php +++ b/modules/user/views/login_ajax.html.php @@ -6,7 +6,7 @@ url: "", success: function(data) { $("div#gLoginView").html(data); - $("#ui-dialog-title-gDialog").text(""); + $("#ui-dialog-title-gDialog").html(for_js() ?>); ajaxify_login_reset_form(); } }); -- cgit v1.2.3 From fe37483aca648b6f7de65f1eb53b8cfd49401f71 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:29:42 -0700 Subject: Update XSS scanner golden file --- modules/gallery/tests/xss_data.txt | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index fa1f8cdf..7e536e90 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -50,7 +50,7 @@ modules/gallery/views/admin_block_news.html.php 5 DIRTY $entry 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 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 $csrf +modules/gallery/views/admin_dashboard.html.php 5 DIRTY_JS $csrf modules/gallery/views/admin_dashboard.html.php 35 DIRTY $blocks modules/gallery/views/admin_graphics.html.php 22 DIRTY newView("admin_graphics_none.html") modules/gallery/views/admin_graphics.html.php 24 DIRTY newView("admin_graphics_$active.html",array("tk"=>$tk->$active,"is_active"=>true)) @@ -88,6 +88,7 @@ modules/gallery/views/admin_maintenance.html.php 146 DIRTY_ATTR $tas modules/gallery/views/admin_maintenance.html.php 147 DIRTY gallery::date_time($task->updated) modules/gallery/views/admin_maintenance.html.php 150 DIRTY $task->name modules/gallery/views/admin_maintenance.html.php 162 DIRTY $task->status +modules/gallery/views/admin_maintenance_show_log.html.php 8 DIRTY_JS url::site("admin/maintenance/save_log/$task->id?csrf=$csrf") modules/gallery/views/admin_maintenance_show_log.html.php 13 DIRTY $task->name modules/gallery/views/admin_maintenance_task.html.php 55 DIRTY $task->name modules/gallery/views/admin_modules.html.php 9 DIRTY access::csrf_form_field() @@ -95,7 +96,8 @@ modules/gallery/views/admin_modules.html.php 19 DIRTY_ATTR ($i% modules/gallery/views/admin_modules.html.php 22 DIRTY form::checkbox($data,'1',module::is_active($module_name)) modules/gallery/views/admin_modules.html.php 24 DIRTY $module_info->version modules/gallery/views/admin_theme_options.html.php 5 DIRTY $form -modules/gallery/views/admin_themes.html.php 5 DIRTY $csrf +modules/gallery/views/admin_themes.html.php 3 DIRTY_JS url::site("admin/themes/choose") +modules/gallery/views/admin_themes.html.php 5 DIRTY_JS $csrf modules/gallery/views/admin_themes.html.php 20 DIRTY $themes[$site]->name modules/gallery/views/admin_themes.html.php 22 DIRTY $themes[$site]->description modules/gallery/views/admin_themes.html.php 36 DIRTY $info->name @@ -123,6 +125,7 @@ modules/gallery/views/l10n_client.html.php 58 DIRTY form:: modules/gallery/views/l10n_client.html.php 62 DIRTY form::textarea("l10n-edit-plural-translation-many","",' rows="2"') modules/gallery/views/l10n_client.html.php 67 DIRTY form::textarea("l10n-edit-plural-translation-other","",' rows="2"') modules/gallery/views/maintenance.html.php 46 DIRTY user::get_login_form("login/auth_html") +modules/gallery/views/move_browse.html.php 4 DIRTY_JS url::site("move/show_sub_tree/{$source->id}/__TARGETID__") modules/gallery/views/move_browse.html.php 39 DIRTY $tree modules/gallery/views/move_browse.html.php 43 DIRTY access::csrf_form_field() modules/gallery/views/move_tree.html.php 2 DIRTY $parent->thumb_img(array(),25); @@ -134,7 +137,11 @@ modules/gallery/views/move_tree.html.php 11 DIRTY $child modules/gallery/views/move_tree.html.php 13 DIRTY_JS $child->id modules/gallery/views/move_tree.html.php 15 DIRTY_JS $child->id modules/gallery/views/movieplayer.html.php 2 DIRTY html::anchor($item->file_url(true),"",$attrs) -modules/gallery/views/movieplayer.html.php 5 DIRTY $attrs["id"] +modules/gallery/views/movieplayer.html.php 5 DIRTY_JS $attrs["id"] +modules/gallery/views/movieplayer.html.php 7 DIRTY_JS url::abs_file("lib/flowplayer.swf") +modules/gallery/views/movieplayer.html.php 13 DIRTY_JS url::abs_file("lib/flowplayer.h264streaming.swf") +modules/gallery/views/permissions_browse.html.php 3 DIRTY_JS url::site("permissions/form/__ITEM__") +modules/gallery/views/permissions_browse.html.php 16 DIRTY_JS url::site("permissions/change/__CMD__/__GROUP__/__PERM__/__ITEM__?csrf=$csrf") modules/gallery/views/permissions_browse.html.php 41 DIRTY_ATTR $parent->id modules/gallery/views/permissions_browse.html.php 42 DIRTY_JS $parent->id modules/gallery/views/permissions_browse.html.php 47 DIRTY_ATTR $item->id @@ -181,6 +188,10 @@ modules/notification/views/item_deleted.html.php 18 DIRTY_JS $item- 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/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") +modules/organize/views/organize_dialog.html.php 6 DIRTY_JS url::site("organize/tree/__ALBUM_ID__") modules/organize/views/organize_dialog.html.php 22 DIRTY $album_tree modules/organize/views/organize_dialog.html.php 29 DIRTY $micro_thumb_grid modules/organize/views/organize_dialog.html.php 37 DIRTY form::dropdown(array("id"=>"gOrganizeSortColumn"),album::get_sort_order_options(),$album->sort_column) @@ -189,6 +200,7 @@ modules/organize/views/organize_thumb_grid.html.php 3 DIRTY_ATTR $chi modules/organize/views/organize_thumb_grid.html.php 4 DIRTY_ATTR $child->id modules/organize/views/organize_thumb_grid.html.php 5 DIRTY_ATTR $child->is_album()?"gAlbum":"gPhoto" modules/organize/views/organize_thumb_grid.html.php 6 DIRTY $child->thumb_img(array("class"=>"gThumbnail","ref"=>$child->id),90,true) +modules/organize/views/organize_thumb_grid.html.php 14 DIRTY_JS url::site("organize/content/$album->id/".($offset+25)) modules/organize/views/organize_tree.html.php 2 DIRTY_ATTR access::can("edit",$album)?"":"gViewOnly" modules/organize/views/organize_tree.html.php 3 DIRTY_ATTR $album->id modules/organize/views/organize_tree.html.php 6 DIRTY_ATTR $selected&&$album->id==$selected->id?"selected":"" @@ -198,8 +210,8 @@ modules/organize/views/organize_tree.html.php 15 DIRTY_ATTR acce modules/organize/views/organize_tree.html.php 16 DIRTY_ATTR $child->id modules/organize/views/organize_tree.html.php 19 DIRTY_ATTR $child->id modules/recaptcha/views/admin_recaptcha.html.php 10 DIRTY $form -modules/recaptcha/views/admin_recaptcha.html.php 23 DIRTY $public_key -modules/recaptcha/views/form_recaptcha.html.php 7 DIRTY $public_key +modules/recaptcha/views/admin_recaptcha.html.php 23 DIRTY_JS $public_key +modules/recaptcha/views/form_recaptcha.html.php 7 DIRTY_JS $public_key modules/rss/views/feed.mrss.php 10 DIRTY $feed->uri modules/rss/views/feed.mrss.php 13 DIRTY_JS $feed->uri modules/rss/views/feed.mrss.php 16 DIRTY_JS $feed->previous_page_uri @@ -239,14 +251,19 @@ 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 modules/server_add/views/server_add_tree.html.php 12 DIRTY_JS html::js_string($dir) modules/server_add/views/server_add_tree.html.php 20 DIRTY_ATTR is_dir($file)?"ui-icon-folder-collapsed":"ui-icon-document" +modules/server_add/views/server_add_tree_dialog.html.php 3 DIRTY_JS url::site("server_add/children?path=__PATH__") +modules/server_add/views/server_add_tree_dialog.html.php 4 DIRTY_JS url::site("server_add/start?item_id={$item->id}&csrf=$csrf") modules/server_add/views/server_add_tree_dialog.html.php 23 DIRTY $tree -modules/tag/views/admin_tags.html.php 13 DIRTY $csrf +modules/tag/views/admin_tags.html.php 13 DIRTY_JS $csrf modules/tag/views/admin_tags.html.php 50 DIRTY_ATTR $tag->id modules/tag/views/admin_tags.html.php 51 DIRTY $tag->count modules/tag/views/tag_block.html.php 15 DIRTY $cloud modules/tag/views/tag_block.html.php 17 DIRTY $form modules/tag/views/tag_cloud.html.php 4 DIRTY_ATTR (int)(($tag->count/$max_count)*7) modules/tag/views/tag_cloud.html.php 5 DIRTY $tag->count +modules/user/views/admin_users.html.php 3 DIRTY_JS url::site("admin/users/add_user_to_group/__USERID__/__GROUPID__?csrf=$csrf") +modules/user/views/admin_users.html.php 26 DIRTY_JS url::site("admin/users/group/__GROUPID__") +modules/user/views/admin_users.html.php 36 DIRTY_JS url::site("admin/users/remove_user_from_group/__USERID__/__GROUPID__?csrf=$csrf") modules/user/views/admin_users.html.php 67 DIRTY_ATTR $user->id modules/user/views/admin_users.html.php 67 DIRTY_ATTR text::alternate("gOddRow","gEvenRow") modules/user/views/admin_users.html.php 67 DIRTY_ATTR $user->admin?"admin":"" @@ -258,6 +275,7 @@ modules/user/views/admin_users.html.php 121 DIRTY_ATTR ($gr modules/user/views/admin_users.html.php 123 DIRTY $v modules/user/views/admin_users_group.html.php 22 DIRTY_JS $user->id modules/user/views/admin_users_group.html.php 22 DIRTY_JS $group->id +modules/user/views/login_ajax.html.php 6 DIRTY_JS url::site("password/reset") modules/user/views/login_ajax.html.php 37 DIRTY $form modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $width modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $height -- cgit v1.2.3 From b50d7f0d69122e15a91b9838eedeeb5c922040bb Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 11:11:22 -0700 Subject: Fix bug #522 - Handle "save settings" correctly in the "share translations" form. --- modules/gallery/controllers/admin_languages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php index 894daedb..d91e5205 100644 --- a/modules/gallery/controllers/admin_languages.php +++ b/modules/gallery/controllers/admin_languages.php @@ -61,7 +61,7 @@ class Admin_Languages_Controller extends Admin_Controller { return $this->index($form); } - if ($form->sharing->share) { + if ($this->input->post("share")) { l10n_client::submit_translations(); message::success(t("Translations submitted")); } else { -- cgit v1.2.3 From 1d3069145273bcb3514f08fa9eee2dbf55a07b01 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 12:14:23 -0700 Subject: Add missing mark_clean() for t() calls with %attr parameter. --- modules/comment/views/comments.html.php | 2 +- modules/recaptcha/views/admin_recaptcha.html.php | 2 +- themes/default/views/album.html.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index b7ebdf3a..7eb34c20 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -8,7 +8,7 @@ count()): ?>

      comment!", - array("attrs" => "href=\"#add_comment_form\" class=\"showCommentForm\"")) ?> + array("attrs" => html::mark_clean("href=\"#add_comment_form\" class=\"showCommentForm\""))) ?>

        diff --git a/modules/recaptcha/views/admin_recaptcha.html.php b/modules/recaptcha/views/admin_recaptcha.html.php index 35722be4..0a4b1f8f 100644 --- a/modules/recaptcha/views/admin_recaptcha.html.php +++ b/modules/recaptcha/views/admin_recaptcha.html.php @@ -4,7 +4,7 @@

        reCAPTCHA Public/Private Key pair, which is also free. Once registered, the challenge and response strings are evaluated at recaptcha.net to determine if the form content has been entered by a bot.", array("domain_url" => $form->get_key_url, - "recaptcha_url" => html::mark_safe("http://recaptcha.net"))) ?> + "recaptcha_url" => html::mark_clean("http://recaptcha.net"))) ?>

        diff --git a/themes/default/views/album.html.php b/themes/default/views/album.html.php index caabeee3..8bc81a31 100644 --- a/themes/default/views/album.html.php +++ b/themes/default/views/album.html.php @@ -30,7 +30,7 @@ admin || access::can("add", $item)): ?> id") ?>
      • Add some.", - array("attrs" => "href=\"$addurl\" class=\"gDialogLink\"")) ?>
      • + array("attrs" => html::mark_clean("href=\"$addurl\" class=\"gDialogLink\""))) ?>
      • -- cgit v1.2.3 From 95ea310aff41f7c16b0a48ec35a5f47c32a4d801 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 14:39:08 -0700 Subject: Remove unused l10n message --- modules/gallery/views/l10n_client.html.php | 1 - 1 file changed, 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php index 3a43f7d3..b0f424be 100644 --- a/modules/gallery/views/l10n_client.html.php +++ b/modules/gallery/views/l10n_client.html.php @@ -74,7 +74,6 @@
      )#si', - array($this, 'scriptCallback'), $html); - } - - $html = $this->normalize($html, $config, $context); - - $cursor = 0; // our location in the text - $inside_tag = false; // whether or not we're parsing the inside of a tag - $array = array(); // result array - - // This is also treated to mean maintain *column* numbers too - $maintain_line_numbers = $config->get('Core.MaintainLineNumbers'); - - if ($maintain_line_numbers === null) { - // automatically determine line numbering by checking - // if error collection is on - $maintain_line_numbers = $config->get('Core.CollectErrors'); - } - - if ($maintain_line_numbers) { - $current_line = 1; - $current_col = 0; - $length = strlen($html); - } else { - $current_line = false; - $current_col = false; - $length = false; - } - $context->register('CurrentLine', $current_line); - $context->register('CurrentCol', $current_col); - $nl = "\n"; - // how often to manually recalculate. This will ALWAYS be right, - // but it's pretty wasteful. Set to 0 to turn off - $synchronize_interval = $config->get('Core.DirectLexLineNumberSyncInterval'); - - $e = false; - if ($config->get('Core.CollectErrors')) { - $e =& $context->get('ErrorCollector'); - } - - // for testing synchronization - $loops = 0; - - while(++$loops) { - - // $cursor is either at the start of a token, or inside of - // a tag (i.e. there was a < immediately before it), as indicated - // by $inside_tag - - if ($maintain_line_numbers) { - - // $rcursor, however, is always at the start of a token. - $rcursor = $cursor - (int) $inside_tag; - - // Column number is cheap, so we calculate it every round. - // We're interested at the *end* of the newline string, so - // we need to add strlen($nl) == 1 to $nl_pos before subtracting it - // from our "rcursor" position. - $nl_pos = strrpos($html, $nl, $rcursor - $length); - $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); - - // recalculate lines - if ( - $synchronize_interval && // synchronization is on - $cursor > 0 && // cursor is further than zero - $loops % $synchronize_interval === 0 // time to synchronize! - ) { - $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); - } - - } - - $position_next_lt = strpos($html, '<', $cursor); - $position_next_gt = strpos($html, '>', $cursor); - - // triggers on "asdf" but not "asdf " - // special case to set up context - if ($position_next_lt === $cursor) { - $inside_tag = true; - $cursor++; - } - - if (!$inside_tag && $position_next_lt !== false) { - // We are not inside tag and there still is another tag to parse - $token = new - HTMLPurifier_Token_Text( - $this->parseData( - substr( - $html, $cursor, $position_next_lt - $cursor - ) - ) - ); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); - } - $array[] = $token; - $cursor = $position_next_lt + 1; - $inside_tag = true; - continue; - } elseif (!$inside_tag) { - // We are not inside tag but there are no more tags - // If we're already at the end, break - if ($cursor === strlen($html)) break; - // Create Text of rest of string - $token = new - HTMLPurifier_Token_Text( - $this->parseData( - substr( - $html, $cursor - ) - ) - ); - if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); - $array[] = $token; - break; - } elseif ($inside_tag && $position_next_gt !== false) { - // We are in tag and it is well formed - // Grab the internals of the tag - $strlen_segment = $position_next_gt - $cursor; - - if ($strlen_segment < 1) { - // there's nothing to process! - $token = new HTMLPurifier_Token_Text('<'); - $cursor++; - continue; - } - - $segment = substr($html, $cursor, $strlen_segment); - - if ($segment === false) { - // somehow, we attempted to access beyond the end of - // the string, defense-in-depth, reported by Nate Abele - break; - } - - // Check if it's a comment - if ( - substr($segment, 0, 3) === '!--' - ) { - // re-determine segment length, looking for --> - $position_comment_end = strpos($html, '-->', $cursor); - if ($position_comment_end === false) { - // uh oh, we have a comment that extends to - // infinity. Can't be helped: set comment - // end position to end of string - if ($e) $e->send(E_WARNING, 'Lexer: Unclosed comment'); - $position_comment_end = strlen($html); - $end = true; - } else { - $end = false; - } - $strlen_segment = $position_comment_end - $cursor; - $segment = substr($html, $cursor, $strlen_segment); - $token = new - HTMLPurifier_Token_Comment( - substr( - $segment, 3, $strlen_segment - 3 - ) - ); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); - } - $array[] = $token; - $cursor = $end ? $position_comment_end : $position_comment_end + 3; - $inside_tag = false; - continue; - } - - // Check if it's an end tag - $is_end_tag = (strpos($segment,'/') === 0); - if ($is_end_tag) { - $type = substr($segment, 1); - $token = new HTMLPurifier_Token_End($type); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $inside_tag = false; - $cursor = $position_next_gt + 1; - continue; - } - - // Check leading character is alnum, if not, we may - // have accidently grabbed an emoticon. Translate into - // text and go our merry way - if (!ctype_alpha($segment[0])) { - // XML: $segment[0] !== '_' && $segment[0] !== ':' - if ($e) $e->send(E_NOTICE, 'Lexer: Unescaped lt'); - $token = new HTMLPurifier_Token_Text('<'); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $inside_tag = false; - continue; - } - - // Check if it is explicitly self closing, if so, remove - // trailing slash. Remember, we could have a tag like
      , so - // any later token processing scripts must convert improperly - // classified EmptyTags from StartTags. - $is_self_closing = (strrpos($segment,'/') === $strlen_segment-1); - if ($is_self_closing) { - $strlen_segment--; - $segment = substr($segment, 0, $strlen_segment); - } - - // Check if there are any attributes - $position_first_space = strcspn($segment, $this->_whitespace); - - if ($position_first_space >= $strlen_segment) { - if ($is_self_closing) { - $token = new HTMLPurifier_Token_Empty($segment); - } else { - $token = new HTMLPurifier_Token_Start($segment); - } - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $inside_tag = false; - $cursor = $position_next_gt + 1; - continue; - } - - // Grab out all the data - $type = substr($segment, 0, $position_first_space); - $attribute_string = - trim( - substr( - $segment, $position_first_space - ) - ); - if ($attribute_string) { - $attr = $this->parseAttributeString( - $attribute_string - , $config, $context - ); - } else { - $attr = array(); - } - - if ($is_self_closing) { - $token = new HTMLPurifier_Token_Empty($type, $attr); - } else { - $token = new HTMLPurifier_Token_Start($type, $attr); - } - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $cursor = $position_next_gt + 1; - $inside_tag = false; - continue; - } else { - // inside tag, but there's no ending > sign - if ($e) $e->send(E_WARNING, 'Lexer: Missing gt'); - $token = new - HTMLPurifier_Token_Text( - '<' . - $this->parseData( - substr($html, $cursor) - ) - ); - if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); - // no cursor scroll? Hmm... - $array[] = $token; - break; - } - break; - } - - $context->destroy('CurrentLine'); - $context->destroy('CurrentCol'); - return $array; - } - - /** - * PHP 5.0.x compatible substr_count that implements offset and length - */ - protected function substrCount($haystack, $needle, $offset, $length) { - static $oldVersion; - if ($oldVersion === null) { - $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); - } - if ($oldVersion) { - $haystack = substr($haystack, $offset, $length); - return substr_count($haystack, $needle); - } else { - return substr_count($haystack, $needle, $offset, $length); - } - } - - /** - * Takes the inside of an HTML tag and makes an assoc array of attributes. - * - * @param $string Inside of tag excluding name. - * @returns Assoc array of attributes. - */ - public function parseAttributeString($string, $config, $context) { - $string = (string) $string; // quick typecast - - if ($string == '') return array(); // no attributes - - $e = false; - if ($config->get('Core.CollectErrors')) { - $e =& $context->get('ErrorCollector'); - } - - // let's see if we can abort as quickly as possible - // one equal sign, no spaces => one attribute - $num_equal = substr_count($string, '='); - $has_space = strpos($string, ' '); - if ($num_equal === 0 && !$has_space) { - // bool attribute - return array($string => $string); - } elseif ($num_equal === 1 && !$has_space) { - // only one attribute - list($key, $quoted_value) = explode('=', $string); - $quoted_value = trim($quoted_value); - if (!$key) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); - return array(); - } - if (!$quoted_value) return array($key => ''); - $first_char = @$quoted_value[0]; - $last_char = @$quoted_value[strlen($quoted_value)-1]; - - $same_quote = ($first_char == $last_char); - $open_quote = ($first_char == '"' || $first_char == "'"); - - if ( $same_quote && $open_quote) { - // well behaved - $value = substr($quoted_value, 1, strlen($quoted_value) - 2); - } else { - // not well behaved - if ($open_quote) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing end quote'); - $value = substr($quoted_value, 1); - } else { - $value = $quoted_value; - } - } - if ($value === false) $value = ''; - return array($key => $value); - } - - // setup loop environment - $array = array(); // return assoc array of attributes - $cursor = 0; // current position in string (moves forward) - $size = strlen($string); // size of the string (stays the same) - - // if we have unquoted attributes, the parser expects a terminating - // space, so let's guarantee that there's always a terminating space. - $string .= ' '; - - while(true) { - - if ($cursor >= $size) { - break; - } - - $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); - // grab the key - - $key_begin = $cursor; //we're currently at the start of the key - - // scroll past all characters that are the key (not whitespace or =) - $cursor += strcspn($string, $this->_whitespace . '=', $cursor); - - $key_end = $cursor; // now at the end of the key - - $key = substr($string, $key_begin, $key_end - $key_begin); - - if (!$key) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); - $cursor += strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop - continue; // empty key - } - - // scroll past all whitespace - $cursor += strspn($string, $this->_whitespace, $cursor); - - if ($cursor >= $size) { - $array[$key] = $key; - break; - } - - // if the next character is an equal sign, we've got a regular - // pair, otherwise, it's a bool attribute - $first_char = @$string[$cursor]; - - if ($first_char == '=') { - // key="value" - - $cursor++; - $cursor += strspn($string, $this->_whitespace, $cursor); - - if ($cursor === false) { - $array[$key] = ''; - break; - } - - // we might be in front of a quote right now - - $char = @$string[$cursor]; - - if ($char == '"' || $char == "'") { - // it's quoted, end bound is $char - $cursor++; - $value_begin = $cursor; - $cursor = strpos($string, $char, $cursor); - $value_end = $cursor; - } else { - // it's not quoted, end bound is whitespace - $value_begin = $cursor; - $cursor += strcspn($string, $this->_whitespace, $cursor); - $value_end = $cursor; - } - - // we reached a premature end - if ($cursor === false) { - $cursor = $size; - $value_end = $cursor; - } - - $value = substr($string, $value_begin, $value_end - $value_begin); - if ($value === false) $value = ''; - $array[$key] = $this->parseData($value); - $cursor++; - - } else { - // boolattr - if ($key !== '') { - $array[$key] = $key; - } else { - // purely theoretical - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); - } - - } - } - return $array; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php deleted file mode 100644 index 57173455..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php +++ /dev/null @@ -1,106 +0,0 @@ -tokens = array(); - - $string = $this->normalize($string, $config, $context); - - $parser = new XML_HTMLSax3(); - $parser->set_object($this); - $parser->set_element_handler('openHandler','closeHandler'); - $parser->set_data_handler('dataHandler'); - $parser->set_escape_handler('escapeHandler'); - - // doesn't seem to work correctly for attributes - $parser->set_option('XML_OPTION_ENTITIES_PARSED', 1); - - $parser->parse($string); - - return $this->tokens; - - } - - /** - * Open tag event handler, interface is defined by PEAR package. - */ - public function openHandler(&$parser, $name, $attrs, $closed) { - // entities are not resolved in attrs - foreach ($attrs as $key => $attr) { - $attrs[$key] = $this->parseData($attr); - } - if ($closed) { - $this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs); - } else { - $this->tokens[] = new HTMLPurifier_Token_Start($name, $attrs); - } - return true; - } - - /** - * Close tag event handler, interface is defined by PEAR package. - */ - public function closeHandler(&$parser, $name) { - // HTMLSax3 seems to always send empty tags an extra close tag - // check and ignore if you see it: - // [TESTME] to make sure it doesn't overreach - if ($this->tokens[count($this->tokens)-1] instanceof HTMLPurifier_Token_Empty) { - return true; - } - $this->tokens[] = new HTMLPurifier_Token_End($name); - return true; - } - - /** - * Data event handler, interface is defined by PEAR package. - */ - public function dataHandler(&$parser, $data) { - $this->tokens[] = new HTMLPurifier_Token_Text($data); - return true; - } - - /** - * Escaped text handler, interface is defined by PEAR package. - */ - public function escapeHandler(&$parser, $data) { - if (strpos($data, '--') === 0) { - $this->tokens[] = new HTMLPurifier_Token_Comment($data); - } - // CDATA is handled elsewhere, but if it was handled here: - //if (strpos($data, '[CDATA[') === 0) { - // $this->tokens[] = new HTMLPurifier_Token_Text( - // substr($data, 7, strlen($data) - 9) ); - //} - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php deleted file mode 100644 index 0d20c0ce..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php +++ /dev/null @@ -1,3906 +0,0 @@ -normalize($html, $config, $context); - $new_html = $this->wrapHTML($new_html, $config, $context); - try { - $parser = new HTML5($new_html); - $doc = $parser->save(); - } catch (DOMException $e) { - // Uh oh, it failed. Punt to DirectLex. - $lexer = new HTMLPurifier_Lexer_DirectLex(); - $context->register('PH5PError', $e); // save the error, so we can detect it - return $lexer->tokenizeHTML($html, $config, $context); // use original HTML - } - $tokens = array(); - $this->tokenizeDOM( - $doc->getElementsByTagName('html')->item(0)-> // - getElementsByTagName('body')->item(0)-> // - getElementsByTagName('div')->item(0) //
      - , $tokens); - return $tokens; - } - -} - -/* - -Copyright 2007 Jeroen van der Meer - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -class HTML5 { - private $data; - private $char; - private $EOF; - private $state; - private $tree; - private $token; - private $content_model; - private $escape = false; - private $entities = array('AElig;','AElig','AMP;','AMP','Aacute;','Aacute', - 'Acirc;','Acirc','Agrave;','Agrave','Alpha;','Aring;','Aring','Atilde;', - 'Atilde','Auml;','Auml','Beta;','COPY;','COPY','Ccedil;','Ccedil','Chi;', - 'Dagger;','Delta;','ETH;','ETH','Eacute;','Eacute','Ecirc;','Ecirc','Egrave;', - 'Egrave','Epsilon;','Eta;','Euml;','Euml','GT;','GT','Gamma;','Iacute;', - 'Iacute','Icirc;','Icirc','Igrave;','Igrave','Iota;','Iuml;','Iuml','Kappa;', - 'LT;','LT','Lambda;','Mu;','Ntilde;','Ntilde','Nu;','OElig;','Oacute;', - 'Oacute','Ocirc;','Ocirc','Ograve;','Ograve','Omega;','Omicron;','Oslash;', - 'Oslash','Otilde;','Otilde','Ouml;','Ouml','Phi;','Pi;','Prime;','Psi;', - 'QUOT;','QUOT','REG;','REG','Rho;','Scaron;','Sigma;','THORN;','THORN', - 'TRADE;','Tau;','Theta;','Uacute;','Uacute','Ucirc;','Ucirc','Ugrave;', - 'Ugrave','Upsilon;','Uuml;','Uuml','Xi;','Yacute;','Yacute','Yuml;','Zeta;', - 'aacute;','aacute','acirc;','acirc','acute;','acute','aelig;','aelig', - 'agrave;','agrave','alefsym;','alpha;','amp;','amp','and;','ang;','apos;', - 'aring;','aring','asymp;','atilde;','atilde','auml;','auml','bdquo;','beta;', - 'brvbar;','brvbar','bull;','cap;','ccedil;','ccedil','cedil;','cedil', - 'cent;','cent','chi;','circ;','clubs;','cong;','copy;','copy','crarr;', - 'cup;','curren;','curren','dArr;','dagger;','darr;','deg;','deg','delta;', - 'diams;','divide;','divide','eacute;','eacute','ecirc;','ecirc','egrave;', - 'egrave','empty;','emsp;','ensp;','epsilon;','equiv;','eta;','eth;','eth', - 'euml;','euml','euro;','exist;','fnof;','forall;','frac12;','frac12', - 'frac14;','frac14','frac34;','frac34','frasl;','gamma;','ge;','gt;','gt', - 'hArr;','harr;','hearts;','hellip;','iacute;','iacute','icirc;','icirc', - 'iexcl;','iexcl','igrave;','igrave','image;','infin;','int;','iota;', - 'iquest;','iquest','isin;','iuml;','iuml','kappa;','lArr;','lambda;','lang;', - 'laquo;','laquo','larr;','lceil;','ldquo;','le;','lfloor;','lowast;','loz;', - 'lrm;','lsaquo;','lsquo;','lt;','lt','macr;','macr','mdash;','micro;','micro', - 'middot;','middot','minus;','mu;','nabla;','nbsp;','nbsp','ndash;','ne;', - 'ni;','not;','not','notin;','nsub;','ntilde;','ntilde','nu;','oacute;', - 'oacute','ocirc;','ocirc','oelig;','ograve;','ograve','oline;','omega;', - 'omicron;','oplus;','or;','ordf;','ordf','ordm;','ordm','oslash;','oslash', - 'otilde;','otilde','otimes;','ouml;','ouml','para;','para','part;','permil;', - 'perp;','phi;','pi;','piv;','plusmn;','plusmn','pound;','pound','prime;', - 'prod;','prop;','psi;','quot;','quot','rArr;','radic;','rang;','raquo;', - 'raquo','rarr;','rceil;','rdquo;','real;','reg;','reg','rfloor;','rho;', - 'rlm;','rsaquo;','rsquo;','sbquo;','scaron;','sdot;','sect;','sect','shy;', - 'shy','sigma;','sigmaf;','sim;','spades;','sub;','sube;','sum;','sup1;', - 'sup1','sup2;','sup2','sup3;','sup3','sup;','supe;','szlig;','szlig','tau;', - 'there4;','theta;','thetasym;','thinsp;','thorn;','thorn','tilde;','times;', - 'times','trade;','uArr;','uacute;','uacute','uarr;','ucirc;','ucirc', - 'ugrave;','ugrave','uml;','uml','upsih;','upsilon;','uuml;','uuml','weierp;', - 'xi;','yacute;','yacute','yen;','yen','yuml;','yuml','zeta;','zwj;','zwnj;'); - - const PCDATA = 0; - const RCDATA = 1; - const CDATA = 2; - const PLAINTEXT = 3; - - const DOCTYPE = 0; - const STARTTAG = 1; - const ENDTAG = 2; - const COMMENT = 3; - const CHARACTR = 4; - const EOF = 5; - - public function __construct($data) { - $data = str_replace("\r\n", "\n", $data); - $data = str_replace("\r", null, $data); - - $this->data = $data; - $this->char = -1; - $this->EOF = strlen($data); - $this->tree = new HTML5TreeConstructer; - $this->content_model = self::PCDATA; - - $this->state = 'data'; - - while($this->state !== null) { - $this->{$this->state.'State'}(); - } - } - - public function save() { - return $this->tree->save(); - } - - private function char() { - return ($this->char < $this->EOF) - ? $this->data[$this->char] - : false; - } - - private function character($s, $l = 0) { - if($s + $l < $this->EOF) { - if($l === 0) { - return $this->data[$s]; - } else { - return substr($this->data, $s, $l); - } - } - } - - private function characters($char_class, $start) { - return preg_replace('#^(['.$char_class.']+).*#s', '\\1', substr($this->data, $start)); - } - - private function dataState() { - // Consume the next input character - $this->char++; - $char = $this->char(); - - if($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { - /* U+0026 AMPERSAND (&) - When the content model flag is set to one of the PCDATA or RCDATA - states: switch to the entity data state. Otherwise: treat it as per - the "anything else" entry below. */ - $this->state = 'entityData'; - - } elseif($char === '-') { - /* If the content model flag is set to either the RCDATA state or - the CDATA state, and the escape flag is false, and there are at - least three characters before this one in the input stream, and the - last four characters in the input stream, including this one, are - U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, - and U+002D HYPHEN-MINUS (""), - set the escape flag to false. */ - if(($this->content_model === self::RCDATA || - $this->content_model === self::CDATA) && $this->escape === true && - $this->character($this->char, 3) === '-->') { - $this->escape = false; - } - - /* In any case, emit the input character as a character token. - Stay in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - } elseif($this->char === $this->EOF) { - /* EOF - Emit an end-of-file token. */ - $this->EOF(); - - } elseif($this->content_model === self::PLAINTEXT) { - /* When the content model flag is set to the PLAINTEXT state - THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of - the text and emit it as a character token. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => substr($this->data, $this->char) - )); - - $this->EOF(); - - } else { - /* Anything else - THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that - otherwise would also be treated as a character token and emit it - as a single character token. Stay in the data state. */ - $len = strcspn($this->data, '<&', $this->char); - $char = substr($this->data, $this->char, $len); - $this->char += $len - 1; - - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - $this->state = 'data'; - } - } - - private function entityDataState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, emit a U+0026 AMPERSAND character token. - // Otherwise, emit the character token that was returned. - $char = (!$entity) ? '&' : $entity; - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - // Finally, switch to the data state. - $this->state = 'data'; - } - - private function tagOpenState() { - switch($this->content_model) { - case self::RCDATA: - case self::CDATA: - /* If the next input character is a U+002F SOLIDUS (/) character, - consume it and switch to the close tag open state. If the next - input character is not a U+002F SOLIDUS (/) character, emit a - U+003C LESS-THAN SIGN character token and switch to the data - state to process the next input character. */ - if($this->character($this->char + 1) === '/') { - $this->char++; - $this->state = 'closeTagOpen'; - - } else { - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->state = 'data'; - } - break; - - case self::PCDATA: - // If the content model flag is set to the PCDATA state - // Consume the next input character: - $this->char++; - $char = $this->char(); - - if($char === '!') { - /* U+0021 EXCLAMATION MARK (!) - Switch to the markup declaration open state. */ - $this->state = 'markupDeclarationOpen'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the close tag open state. */ - $this->state = 'closeTagOpen'; - - } elseif(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new start tag token, set its tag name to the lowercase - version of the input character (add 0x0020 to the character's code - point), then switch to the tag name state. (Don't emit the token - yet; further details will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::STARTTAG, - 'attr' => array() - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit a U+003C LESS-THAN SIGN character token and a - U+003E GREATER-THAN SIGN character token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<>' - )); - - $this->state = 'data'; - - } elseif($char === '?') { - /* U+003F QUESTION MARK (?) - Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - - } else { - /* Anything else - Parse error. Emit a U+003C LESS-THAN SIGN character token and - reconsume the current input character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->char--; - $this->state = 'data'; - } - break; - } - } - - private function closeTagOpenState() { - $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); - $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; - - if(($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && - (!$the_same || ($the_same && (!preg_match('/[\t\n\x0b\x0c >\/]/', - $this->character($this->char + 1 + strlen($next_node))) || $this->EOF === $this->char)))) { - /* If the content model flag is set to the RCDATA or CDATA states then - examine the next few characters. If they do not match the tag name of - the last start tag token emitted (case insensitively), or if they do but - they are not immediately followed by one of the following characters: - * U+0009 CHARACTER TABULATION - * U+000A LINE FEED (LF) - * U+000B LINE TABULATION - * U+000C FORM FEED (FF) - * U+0020 SPACE - * U+003E GREATER-THAN SIGN (>) - * U+002F SOLIDUS (/) - * EOF - ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character - token, a U+002F SOLIDUS character token, and switch to the data state - to process the next input character. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'state = 'data'; - - } else { - /* Otherwise, if the content model flag is set to the PCDATA state, - or if the next few characters do match that tag name, consume the - next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new end tag token, set its tag name to the lowercase version - of the input character (add 0x0020 to the character's code point), then - switch to the tag name state. (Don't emit the token yet; further details - will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::ENDTAG - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Switch to the data state. */ - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F - SOLIDUS character token. Reconsume the EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'char--; - $this->state = 'data'; - - } else { - /* Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - } - } - } - - private function tagNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } else { - /* Anything else - Append the current input character to the current tag token's tag name. - Stay in the tag name state. */ - $this->token['name'] .= strtolower($char); - $this->state = 'tagName'; - } - } - - private function beforeAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Stay in the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function attributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's name. - Stay in the attribute name state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= strtolower($char); - - $this->state = 'attributeName'; - } - } - - private function afterAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the - before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function beforeAttributeValueState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the attribute value (double-quoted) state. */ - $this->state = 'attributeValueDoubleQuoted'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the attribute value (unquoted) state and reconsume - this input character. */ - $this->char--; - $this->state = 'attributeValueUnquoted'; - - } elseif($char === '\'') { - /* U+0027 APOSTROPHE (') - Switch to the attribute value (single-quoted) state. */ - $this->state = 'attributeValueSingleQuoted'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Switch to the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function attributeValueDoubleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('double'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (double-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueDoubleQuoted'; - } - } - - private function attributeValueSingleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '\'') { - /* U+0022 QUOTATION MARK (') - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('single'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (single-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueSingleQuoted'; - } - } - - private function attributeValueUnquotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState(); - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function entityInAttributeValueState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, append a U+0026 AMPERSAND character to the - // current attribute's value. Otherwise, emit the character token that - // was returned. - $char = (!$entity) - ? '&' - : $entity; - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - } - - private function bogusCommentState() { - /* Consume every character up to the first U+003E GREATER-THAN SIGN - character (>) or the end of the file (EOF), whichever comes first. Emit - a comment token whose data is the concatenation of all the characters - starting from and including the character that caused the state machine - to switch into the bogus comment state, up to and including the last - consumed character before the U+003E character, if any, or up to the - end of the file otherwise. (If the comment was started by the end of - the file (EOF), the token is empty.) */ - $data = $this->characters('^>', $this->char); - $this->emitToken(array( - 'data' => $data, - 'type' => self::COMMENT - )); - - $this->char += strlen($data); - - /* Switch to the data state. */ - $this->state = 'data'; - - /* If the end of the file was reached, reconsume the EOF character. */ - if($this->char === $this->EOF) { - $this->char = $this->EOF - 1; - } - } - - private function markupDeclarationOpenState() { - /* If the next two characters are both U+002D HYPHEN-MINUS (-) - characters, consume those two characters, create a comment token whose - data is the empty string, and switch to the comment state. */ - if($this->character($this->char + 1, 2) === '--') { - $this->char += 2; - $this->state = 'comment'; - $this->token = array( - 'data' => null, - 'type' => self::COMMENT - ); - - /* Otherwise if the next seven chacacters are a case-insensitive match - for the word "DOCTYPE", then consume those characters and switch to the - DOCTYPE state. */ - } elseif(strtolower($this->character($this->char + 1, 7)) === 'doctype') { - $this->char += 7; - $this->state = 'doctype'; - - /* Otherwise, is is a parse error. Switch to the bogus comment state. - The next character that is consumed, if any, is the first character - that will be in the comment. */ - } else { - $this->char++; - $this->state = 'bogusComment'; - } - } - - private function commentState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment dash state */ - $this->state = 'commentDash'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append the input character to the comment token's data. Stay in - the comment state. */ - $this->token['data'] .= $char; - } - } - - private function commentDashState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment end state */ - $this->state = 'commentEnd'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append a U+002D HYPHEN-MINUS (-) character and the input - character to the comment token's data. Switch to the comment state. */ - $this->token['data'] .= '-'.$char; - $this->state = 'comment'; - } - } - - private function commentEndState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '-') { - $this->token['data'] .= '-'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['data'] .= '--'.$char; - $this->state = 'comment'; - } - } - - private function doctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'beforeDoctypeName'; - - } else { - $this->char--; - $this->state = 'beforeDoctypeName'; - } - } - - private function beforeDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the before DOCTYPE name state. - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token = array( - 'name' => strtoupper($char), - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - - } elseif($char === '>') { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->char--; - $this->state = 'data'; - - } else { - $this->token = array( - 'name' => $char, - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - } - } - - private function doctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'AfterDoctypeName'; - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token['name'] .= strtoupper($char); - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['name'] .= $char; - } - - $this->token['error'] = ($this->token['name'] === 'HTML') - ? false - : true; - } - - private function afterDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the DOCTYPE name state. - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['error'] = true; - $this->state = 'bogusDoctype'; - } - } - - private function bogusDoctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - // Stay in the bogus DOCTYPE state. - } - } - - private function entity() { - $start = $this->char; - - // This section defines how to consume an entity. This definition is - // used when parsing entities in text and in attributes. - - // The behaviour depends on the identity of the next character (the - // one immediately after the U+0026 AMPERSAND character): - - switch($this->character($this->char + 1)) { - // U+0023 NUMBER SIGN (#) - case '#': - - // The behaviour further depends on the character after the - // U+0023 NUMBER SIGN: - switch($this->character($this->char + 1)) { - // U+0078 LATIN SMALL LETTER X - // U+0058 LATIN CAPITAL LETTER X - case 'x': - case 'X': - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 - // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER - // A, through to U+0046 LATIN CAPITAL LETTER F (in other - // words, 0-9, A-F, a-f). - $char = 1; - $char_class = '0-9A-Fa-f'; - break; - - // Anything else - default: - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE (i.e. just 0-9). - $char = 0; - $char_class = '0-9'; - break; - } - - // Consume as many characters as match the range of characters - // given above. - $this->char++; - $e_name = $this->characters($char_class, $this->char + $char + 1); - $entity = $this->character($start, $this->char); - $cond = strlen($e_name) > 0; - - // The rest of the parsing happens bellow. - break; - - // Anything else - default: - // Consume the maximum number of characters possible, with the - // consumed characters case-sensitively matching one of the - // identifiers in the first column of the entities table. - $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); - $len = strlen($e_name); - - for($c = 1; $c <= $len; $c++) { - $id = substr($e_name, 0, $c); - $this->char++; - - if(in_array($id, $this->entities)) { - if ($e_name[$c-1] !== ';') { - if ($c < $len && $e_name[$c] == ';') { - $this->char++; // consume extra semicolon - } - } - $entity = $id; - break; - } - } - - $cond = isset($entity); - // The rest of the parsing happens bellow. - break; - } - - if(!$cond) { - // If no match can be made, then this is a parse error. No - // characters are consumed, and nothing is returned. - $this->char = $start; - return false; - } - - // Return a character token for the character corresponding to the - // entity name (as given by the second column of the entities table). - return html_entity_decode('&'.$entity.';', ENT_QUOTES, 'UTF-8'); - } - - private function emitToken($token) { - $emit = $this->tree->emitToken($token); - - if(is_int($emit)) { - $this->content_model = $emit; - - } elseif($token['type'] === self::ENDTAG) { - $this->content_model = self::PCDATA; - } - } - - private function EOF() { - $this->state = null; - $this->tree->emitToken(array( - 'type' => self::EOF - )); - } -} - -class HTML5TreeConstructer { - public $stack = array(); - - private $phase; - private $mode; - private $dom; - private $foster_parent = null; - private $a_formatting = array(); - - private $head_pointer = null; - private $form_pointer = null; - - private $scoping = array('button','caption','html','marquee','object','table','td','th'); - private $formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u'); - private $special = array('address','area','base','basefont','bgsound', - 'blockquote','body','br','center','col','colgroup','dd','dir','div','dl', - 'dt','embed','fieldset','form','frame','frameset','h1','h2','h3','h4','h5', - 'h6','head','hr','iframe','image','img','input','isindex','li','link', - 'listing','menu','meta','noembed','noframes','noscript','ol','optgroup', - 'option','p','param','plaintext','pre','script','select','spacer','style', - 'tbody','textarea','tfoot','thead','title','tr','ul','wbr'); - - // The different phases. - const INIT_PHASE = 0; - const ROOT_PHASE = 1; - const MAIN_PHASE = 2; - const END_PHASE = 3; - - // The different insertion modes for the main phase. - const BEFOR_HEAD = 0; - const IN_HEAD = 1; - const AFTER_HEAD = 2; - const IN_BODY = 3; - const IN_TABLE = 4; - const IN_CAPTION = 5; - const IN_CGROUP = 6; - const IN_TBODY = 7; - const IN_ROW = 8; - const IN_CELL = 9; - const IN_SELECT = 10; - const AFTER_BODY = 11; - const IN_FRAME = 12; - const AFTR_FRAME = 13; - - // The different types of elements. - const SPECIAL = 0; - const SCOPING = 1; - const FORMATTING = 2; - const PHRASING = 3; - - const MARKER = 0; - - public function __construct() { - $this->phase = self::INIT_PHASE; - $this->mode = self::BEFOR_HEAD; - $this->dom = new DOMDocument; - - $this->dom->encoding = 'UTF-8'; - $this->dom->preserveWhiteSpace = true; - $this->dom->substituteEntities = true; - $this->dom->strictErrorChecking = false; - } - - // Process tag tokens - public function emitToken($token) { - switch($this->phase) { - case self::INIT_PHASE: return $this->initPhase($token); break; - case self::ROOT_PHASE: return $this->rootElementPhase($token); break; - case self::MAIN_PHASE: return $this->mainPhase($token); break; - case self::END_PHASE : return $this->trailingEndPhase($token); break; - } - } - - private function initPhase($token) { - /* Initially, the tree construction stage must handle each token - emitted from the tokenisation stage as follows: */ - - /* A DOCTYPE token that is marked as being in error - A comment token - A start tag token - An end tag token - A character token that is not one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE - An end-of-file token */ - if((isset($token['error']) && $token['error']) || - $token['type'] === HTML5::COMMENT || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF || - ($token['type'] === HTML5::CHARACTR && isset($token['data']) && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) { - /* This specification does not define how to handle this case. In - particular, user agents may ignore the entirety of this specification - altogether for such documents, and instead invoke special parse modes - with a greater emphasis on backwards compatibility. */ - - $this->phase = self::ROOT_PHASE; - return $this->rootElementPhase($token); - - /* A DOCTYPE token marked as being correct */ - } elseif(isset($token['error']) && !$token['error']) { - /* Append a DocumentType node to the Document node, with the name - attribute set to the name given in the DOCTYPE token (which will be - "HTML"), and the other attributes specific to DocumentType objects - set to null, empty lists, or the empty string as appropriate. */ - $doctype = new DOMDocumentType(null, null, 'HTML'); - - /* Then, switch to the root element phase of the tree construction - stage. */ - $this->phase = self::ROOT_PHASE; - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/', - $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - } - } - - private function rootElementPhase($token) { - /* After the initial phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED - (FF), or U+0020 SPACE - A start tag token - An end tag token - An end-of-file token */ - } elseif(($token['type'] === HTML5::CHARACTR && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF) { - /* Create an HTMLElement node with the tag name html, in the HTML - namespace. Append it to the Document object. Switch to the main - phase and reprocess the current token. */ - $html = $this->dom->createElement('html'); - $this->dom->appendChild($html); - $this->stack[] = $html; - - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - } - } - - private function mainPhase($token) { - /* Tokens in the main phase must be handled as follows: */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A start tag token with the tag name "html" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { - /* If this start tag token was not the first start tag token, then - it is a parse error. */ - - /* For each attribute on the token, check to see if the attribute - is already present on the top element of the stack of open elements. - If it is not, add the attribute and its corresponding value to that - element. */ - foreach($token['attr'] as $attr) { - if(!$this->stack[0]->hasAttribute($attr['name'])) { - $this->stack[0]->setAttribute($attr['name'], $attr['value']); - } - } - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Anything else. */ - } else { - /* Depends on the insertion mode: */ - switch($this->mode) { - case self::BEFOR_HEAD: return $this->beforeHead($token); break; - case self::IN_HEAD: return $this->inHead($token); break; - case self::AFTER_HEAD: return $this->afterHead($token); break; - case self::IN_BODY: return $this->inBody($token); break; - case self::IN_TABLE: return $this->inTable($token); break; - case self::IN_CAPTION: return $this->inCaption($token); break; - case self::IN_CGROUP: return $this->inColumnGroup($token); break; - case self::IN_TBODY: return $this->inTableBody($token); break; - case self::IN_ROW: return $this->inRow($token); break; - case self::IN_CELL: return $this->inCell($token); break; - case self::IN_SELECT: return $this->inSelect($token); break; - case self::AFTER_BODY: return $this->afterBody($token); break; - case self::IN_FRAME: return $this->inFrameset($token); break; - case self::AFTR_FRAME: return $this->afterFrameset($token); break; - case self::END_PHASE: return $this->trailingEndPhase($token); break; - } - } - } - - private function beforeHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "head" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { - /* Create an element for the token, append the new element to the - current node and push it onto the stack of open elements. */ - $element = $this->insertElement($token); - - /* Set the head element pointer to this new element node. */ - $this->head_pointer = $element; - - /* Change the insertion mode to "in head". */ - $this->mode = self::IN_HEAD; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title". Or an end tag with the tag name "html". - Or a character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or any other start tag token */ - } elseif($token['type'] === HTML5::STARTTAG || - ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || - ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/', - $token['data']))) { - /* Act as if a start tag token with the tag name "head" and no - attributes had been seen, then reprocess the current token. */ - $this->beforeHead(array( - 'name' => 'head', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inHead($token); - - /* Any other end tag */ - } elseif($token['type'] === HTML5::ENDTAG) { - /* Parse error. Ignore the token. */ - } - } - - private function inHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. - - THIS DIFFERS FROM THE SPEC: If the current node is either a title, style - or script element, append the character to the current node regardless - of its content. */ - if(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( - $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName, - array('title', 'style', 'script')))) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('title', 'style', 'script'))) { - array_pop($this->stack); - return HTML5::PCDATA; - - /* A start tag with the tag name "title" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $element = $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the RCDATA state. */ - return HTML5::RCDATA; - - /* A start tag with the tag name "style" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "script" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { - /* Create an element for the token. */ - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "base", "link", or "meta" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta'))) { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - array_pop($this->stack); - - } else { - $this->insertElement($token); - } - - /* An end tag with the tag name "head" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { - /* If the current node is a head element, pop the current node off - the stack of open elements. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - array_pop($this->stack); - - /* Otherwise, this is a parse error. */ - } else { - // k - } - - /* Change the insertion mode to "after head". */ - $this->mode = self::AFTER_HEAD; - - /* A start tag with the tag name "head" or an end tag except "html". */ - } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* If the current node is a head element, act as if an end tag - token with the tag name "head" had been seen. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - $this->inHead(array( - 'name' => 'head', - 'type' => HTML5::ENDTAG - )); - - /* Otherwise, change the insertion mode to "after head". */ - } else { - $this->mode = self::AFTER_HEAD; - } - - /* Then, reprocess the current token. */ - return $this->afterHead($token); - } - } - - private function afterHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "body" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { - /* Insert a body element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in body". */ - $this->mode = self::IN_BODY; - - /* A start tag token with the tag name "frameset" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { - /* Insert a frameset element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in frameset". */ - $this->mode = self::IN_FRAME; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta', 'script', 'style', 'title'))) { - /* Parse error. Switch the insertion mode back to "in head" and - reprocess the token. */ - $this->mode = self::IN_HEAD; - return $this->inHead($token); - - /* Anything else */ - } else { - /* Act as if a start tag token with the tag name "body" and no - attributes had been seen, and then reprocess the current token. */ - $this->afterHead(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inBody($token); - } - } - - private function inBody($token) { - /* Handle the token as follows: */ - - switch($token['type']) { - /* A character token */ - case HTML5::CHARACTR: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - break; - - /* A comment token */ - case HTML5::COMMENT: - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - break; - - case HTML5::STARTTAG: - switch($token['name']) { - /* A start tag token whose tag name is one of: "script", - "style" */ - case 'script': case 'style': - /* Process the token as if the insertion mode had been "in - head". */ - return $this->inHead($token); - break; - - /* A start tag token whose tag name is one of: "base", "link", - "meta", "title" */ - case 'base': case 'link': case 'meta': case 'title': - /* Parse error. Process the token as if the insertion mode - had been "in head". */ - return $this->inHead($token); - break; - - /* A start tag token with the tag name "body" */ - case 'body': - /* Parse error. If the second element on the stack of open - elements is not a body element, or, if the stack of open - elements has only one node on it, then ignore the token. - (innerHTML case) */ - if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { - // Ignore - - /* Otherwise, for each attribute on the token, check to see - if the attribute is already present on the body element (the - second element) on the stack of open elements. If it is not, - add the attribute and its corresponding value to that - element. */ - } else { - foreach($token['attr'] as $attr) { - if(!$this->stack[1]->hasAttribute($attr['name'])) { - $this->stack[1]->setAttribute($attr['name'], $attr['value']); - } - } - } - break; - - /* A start tag whose tag name is one of: "address", - "blockquote", "center", "dir", "div", "dl", "fieldset", - "listing", "menu", "ol", "p", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'p': case 'ul': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "form" */ - case 'form': - /* If the form element pointer is not null, ignore the - token with a parse error. */ - if($this->form_pointer !== null) { - // Ignore. - - /* Otherwise: */ - } else { - /* If the stack of open elements has a p element in - scope, then act as if an end tag with the tag name p - had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token, and set the - form element pointer to point to the element created. */ - $element = $this->insertElement($token); - $this->form_pointer = $element; - } - break; - - /* A start tag whose tag name is "li", "dd" or "dt" */ - case 'li': case 'dd': case 'dt': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - $stack_length = count($this->stack) - 1; - - for($n = $stack_length; 0 <= $n; $n--) { - /* 1. Initialise node to be the current node (the - bottommost node of the stack). */ - $stop = false; - $node = $this->stack[$n]; - $cat = $this->getElementCategory($node->tagName); - - /* 2. If node is an li, dd or dt element, then pop all - the nodes from the current node up to node, including - node, then stop this algorithm. */ - if($token['name'] === $node->tagName || ($token['name'] !== 'li' - && ($node->tagName === 'dd' || $node->tagName === 'dt'))) { - for($x = $stack_length; $x >= $n ; $x--) { - array_pop($this->stack); - } - - break; - } - - /* 3. If node is not in the formatting category, and is - not in the phrasing category, and is not an address or - div element, then stop this algorithm. */ - if($cat !== self::FORMATTING && $cat !== self::PHRASING && - $node->tagName !== 'address' && $node->tagName !== 'div') { - break; - } - } - - /* Finally, insert an HTML element with the same tag - name as the token's. */ - $this->insertElement($token); - break; - - /* A start tag token whose tag name is "plaintext" */ - case 'plaintext': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - return HTML5::PLAINTEXT; - break; - - /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - this is a parse error; pop elements from the stack until an - element with one of those tag names has been popped from the - stack. */ - while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { - array_pop($this->stack); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "a" */ - case 'a': - /* If the list of active formatting elements contains - an element whose tag name is "a" between the end of the - list and the last marker on the list (or the start of - the list if there is no marker on the list), then this - is a parse error; act as if an end tag with the tag name - "a" had been seen, then remove that element from the list - of active formatting elements and the stack of open - elements if the end tag didn't already remove it (it - might not have if the element is not in table scope). */ - $leng = count($this->a_formatting); - - for($n = $leng - 1; $n >= 0; $n--) { - if($this->a_formatting[$n] === self::MARKER) { - break; - - } elseif($this->a_formatting[$n]->nodeName === 'a') { - $this->emitToken(array( - 'name' => 'a', - 'type' => HTML5::ENDTAG - )); - break; - } - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag whose tag name is one of: "b", "big", "em", "font", - "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'b': case 'big': case 'em': case 'font': case 'i': - case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag token whose tag name is "button" */ - case 'button': - /* If the stack of open elements has a button element in scope, - then this is a parse error; act as if an end tag with the tag - name "button" had been seen, then reprocess the token. (We don't - do that. Unnecessary.) */ - if($this->elementInScope('button')) { - $this->inBody(array( - 'name' => 'button', - 'type' => HTML5::ENDTAG - )); - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is one of: "marquee", "object" */ - case 'marquee': case 'object': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is "xmp" */ - case 'xmp': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Switch the content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "table" */ - case 'table': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - break; - - /* A start tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'img': case 'param': case 'spacer': - case 'wbr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "hr" */ - case 'hr': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "image" */ - case 'image': - /* Parse error. Change the token's tag name to "img" and - reprocess it. (Don't ask.) */ - $token['name'] = 'img'; - return $this->inBody($token); - break; - - /* A start tag whose tag name is "input" */ - case 'input': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an input element for the token. */ - $element = $this->insertElement($token, false); - - /* If the form element pointer is not null, then associate the - input element with the form element pointed to by the form - element pointer. */ - $this->form_pointer !== null - ? $this->form_pointer->appendChild($element) - : end($this->stack)->appendChild($element); - - /* Pop that input element off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "isindex" */ - case 'isindex': - /* Parse error. */ - // w/e - - /* If the form element pointer is not null, - then ignore the token. */ - if($this->form_pointer === null) { - /* Act as if a start tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a stream of character tokens had been seen. */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if a start tag token with the tag name "input" - had been seen, with all the attributes from the "isindex" - token, except with the "name" attribute set to the value - "isindex" (ignoring any explicit "name" attribute). */ - $attr = $token['attr']; - $attr[] = array('name' => 'name', 'value' => 'isindex'); - - $this->inBody(array( - 'name' => 'input', - 'type' => HTML5::STARTTAG, - 'attr' => $attr - )); - - /* Act as if a stream of character tokens had been seen - (see below for what they should say). */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if an end tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'form', - 'type' => HTML5::ENDTAG - )); - } - break; - - /* A start tag whose tag name is "textarea" */ - case 'textarea': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the - RCDATA state. */ - return HTML5::RCDATA; - break; - - /* A start tag whose tag name is one of: "iframe", "noembed", - "noframes" */ - case 'iframe': case 'noembed': case 'noframes': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "select" */ - case 'select': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in select". */ - $this->mode = self::IN_SELECT; - break; - - /* A start or end tag whose tag name is one of: "caption", "col", - "colgroup", "frame", "frameset", "head", "option", "optgroup", - "tbody", "td", "tfoot", "th", "thead", "tr". */ - case 'caption': case 'col': case 'colgroup': case 'frame': - case 'frameset': case 'head': case 'option': case 'optgroup': - case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': - case 'tr': - // Parse error. Ignore the token. - break; - - /* A start or end tag whose tag name is one of: "event-source", - "section", "nav", "article", "aside", "header", "footer", - "datagrid", "command" */ - case 'event-source': case 'section': case 'nav': case 'article': - case 'aside': case 'header': case 'footer': case 'datagrid': - case 'command': - // Work in progress! - break; - - /* A start tag token not covered by the previous entries */ - default: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - $this->insertElement($token, true, true); - break; - } - break; - - case HTML5::ENDTAG: - switch($token['name']) { - /* An end tag with the tag name "body" */ - case 'body': - /* If the second element in the stack of open elements is - not a body element, this is a parse error. Ignore the token. - (innerHTML case) */ - if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { - // Ignore. - - /* If the current node is not the body element, then this - is a parse error. */ - } elseif(end($this->stack)->nodeName !== 'body') { - // Parse error. - } - - /* Change the insertion mode to "after body". */ - $this->mode = self::AFTER_BODY; - break; - - /* An end tag with the tag name "html" */ - case 'html': - /* Act as if an end tag with tag name "body" had been seen, - then, if that token wasn't ignored, reprocess the current - token. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::ENDTAG - )); - - return $this->afterBody($token); - break; - - /* An end tag whose tag name is one of: "address", "blockquote", - "center", "dir", "div", "dl", "fieldset", "listing", "menu", - "ol", "pre", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'pre': case 'ul': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with - the same tag name as that of the token, then this - is a parse error. */ - // w/e - - /* If the stack of open elements has an element in - scope with the same tag name as that of the token, - then pop elements from this stack until an element - with that tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is "form" */ - case 'form': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - } - - if(end($this->stack)->nodeName !== $token['name']) { - /* Now, if the current node is not an element with the - same tag name as that of the token, then this is a parse - error. */ - // w/e - - } else { - /* Otherwise, if the current node is an element with - the same tag name as that of the token pop that element - from the stack. */ - array_pop($this->stack); - } - - /* In any case, set the form element pointer to null. */ - $this->form_pointer = null; - break; - - /* An end tag whose tag name is "p" */ - case 'p': - /* If the stack of open elements has a p element in scope, - then generate implied end tags, except for p elements. */ - if($this->elementInScope('p')) { - $this->generateImpliedEndTags(array('p')); - - /* If the current node is not a p element, then this is - a parse error. */ - // k - - /* If the stack of open elements has a p element in - scope, then pop elements from this stack until the stack - no longer has a p element in scope. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->elementInScope('p')) { - array_pop($this->stack); - - } else { - break; - } - } - } - break; - - /* An end tag whose tag name is "dd", "dt", or "li" */ - case 'dd': case 'dt': case 'li': - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - generate implied end tags, except for elements with the - same tag name as the token. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(array($token['name'])); - - /* If the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - pop elements from this stack until an element with that - tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - generate implied end tags. */ - if($this->elementInScope($elements)) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as that of the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has in scope an element - whose tag name is one of "h1", "h2", "h3", "h4", "h5", or - "h6", then pop elements from the stack until an element - with one of those tag names has been popped from the stack. */ - while($this->elementInScope($elements)) { - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "a", "b", "big", "em", - "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'a': case 'b': case 'big': case 'em': case 'font': - case 'i': case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* 1. Let the formatting element be the last element in - the list of active formatting elements that: - * is between the end of the list and the last scope - marker in the list, if any, or the start of the list - otherwise, and - * has the same tag name as the token. - */ - while(true) { - for($a = count($this->a_formatting) - 1; $a >= 0; $a--) { - if($this->a_formatting[$a] === self::MARKER) { - break; - - } elseif($this->a_formatting[$a]->tagName === $token['name']) { - $formatting_element = $this->a_formatting[$a]; - $in_stack = in_array($formatting_element, $this->stack, true); - $fe_af_pos = $a; - break; - } - } - - /* If there is no such node, or, if that node is - also in the stack of open elements but the element - is not in scope, then this is a parse error. Abort - these steps. The token is ignored. */ - if(!isset($formatting_element) || ($in_stack && - !$this->elementInScope($token['name']))) { - break; - - /* Otherwise, if there is such a node, but that node - is not in the stack of open elements, then this is a - parse error; remove the element from the list, and - abort these steps. */ - } elseif(isset($formatting_element) && !$in_stack) { - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 2. Let the furthest block be the topmost node in the - stack of open elements that is lower in the stack - than the formatting element, and is not an element in - the phrasing or formatting categories. There might - not be one. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $length = count($this->stack); - - for($s = $fe_s_pos + 1; $s < $length; $s++) { - $category = $this->getElementCategory($this->stack[$s]->nodeName); - - if($category !== self::PHRASING && $category !== self::FORMATTING) { - $furthest_block = $this->stack[$s]; - } - } - - /* 3. If there is no furthest block, then the UA must - skip the subsequent steps and instead just pop all - the nodes from the bottom of the stack of open - elements, from the current node up to the formatting - element, and remove the formatting element from the - list of active formatting elements. */ - if(!isset($furthest_block)) { - for($n = $length - 1; $n >= $fe_s_pos; $n--) { - array_pop($this->stack); - } - - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 4. Let the common ancestor be the element - immediately above the formatting element in the stack - of open elements. */ - $common_ancestor = $this->stack[$fe_s_pos - 1]; - - /* 5. If the furthest block has a parent node, then - remove the furthest block from its parent node. */ - if($furthest_block->parentNode !== null) { - $furthest_block->parentNode->removeChild($furthest_block); - } - - /* 6. Let a bookmark note the position of the - formatting element in the list of active formatting - elements relative to the elements on either side - of it in the list. */ - $bookmark = $fe_af_pos; - - /* 7. Let node and last node be the furthest block. - Follow these steps: */ - $node = $furthest_block; - $last_node = $furthest_block; - - while(true) { - for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { - /* 7.1 Let node be the element immediately - prior to node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 7.2 If node is not in the list of active - formatting elements, then remove node from - the stack of open elements and then go back - to step 1. */ - if(!in_array($node, $this->a_formatting, true)) { - unset($this->stack[$n]); - $this->stack = array_merge($this->stack); - - } else { - break; - } - } - - /* 7.3 Otherwise, if node is the formatting - element, then go to the next step in the overall - algorithm. */ - if($node === $formatting_element) { - break; - - /* 7.4 Otherwise, if last node is the furthest - block, then move the aforementioned bookmark to - be immediately after the node in the list of - active formatting elements. */ - } elseif($last_node === $furthest_block) { - $bookmark = array_search($node, $this->a_formatting, true) + 1; - } - - /* 7.5 If node has any children, perform a - shallow clone of node, replace the entry for - node in the list of active formatting elements - with an entry for the clone, replace the entry - for node in the stack of open elements with an - entry for the clone, and let node be the clone. */ - if($node->hasChildNodes()) { - $clone = $node->cloneNode(); - $s_pos = array_search($node, $this->stack, true); - $a_pos = array_search($node, $this->a_formatting, true); - - $this->stack[$s_pos] = $clone; - $this->a_formatting[$a_pos] = $clone; - $node = $clone; - } - - /* 7.6 Insert last node into node, first removing - it from its previous parent node if any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $node->appendChild($last_node); - - /* 7.7 Let last node be node. */ - $last_node = $node; - } - - /* 8. Insert whatever last node ended up being in - the previous step into the common ancestor node, - first removing it from its previous parent node if - any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $common_ancestor->appendChild($last_node); - - /* 9. Perform a shallow clone of the formatting - element. */ - $clone = $formatting_element->cloneNode(); - - /* 10. Take all of the child nodes of the furthest - block and append them to the clone created in the - last step. */ - while($furthest_block->hasChildNodes()) { - $child = $furthest_block->firstChild; - $furthest_block->removeChild($child); - $clone->appendChild($child); - } - - /* 11. Append that clone to the furthest block. */ - $furthest_block->appendChild($clone); - - /* 12. Remove the formatting element from the list - of active formatting elements, and insert the clone - into the list of active formatting elements at the - position of the aforementioned bookmark. */ - $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - - $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); - $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); - $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); - - /* 13. Remove the formatting element from the stack - of open elements, and insert the clone into the stack - of open elements immediately after (i.e. in a more - deeply nested position than) the position of the - furthest block in that stack. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $fb_s_pos = array_search($furthest_block, $this->stack, true); - unset($this->stack[$fe_s_pos]); - - $s_part1 = array_slice($this->stack, 0, $fb_s_pos); - $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); - $this->stack = array_merge($s_part1, array($clone), $s_part2); - - /* 14. Jump back to step 1 in this series of steps. */ - unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); - } - break; - - /* An end tag token whose tag name is one of: "button", - "marquee", "object" */ - case 'button': case 'marquee': case 'object': - /* If the stack of open elements has an element in scope whose - tag name matches the tag name of the token, then generate implied - tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // k - - /* Now, if the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then pop - elements from the stack until that element has been popped from - the stack, and clear the list of active formatting elements up - to the last marker. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - - $marker = end(array_keys($this->a_formatting, self::MARKER, true)); - - for($n = count($this->a_formatting) - 1; $n > $marker; $n--) { - array_pop($this->a_formatting); - } - } - break; - - /* Or an end tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "hr", "iframe", "image", "img", - "input", "isindex", "noembed", "noframes", "param", "select", - "spacer", "table", "textarea", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'hr': case 'iframe': case 'image': - case 'img': case 'input': case 'isindex': case 'noembed': - case 'noframes': case 'param': case 'select': case 'spacer': - case 'table': case 'textarea': case 'wbr': - // Parse error. Ignore the token. - break; - - /* An end tag token not covered by the previous entries */ - default: - for($n = count($this->stack) - 1; $n >= 0; $n--) { - /* Initialise node to be the current node (the bottommost - node of the stack). */ - $node = end($this->stack); - - /* If node has the same tag name as the end tag token, - then: */ - if($token['name'] === $node->nodeName) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* If the tag name of the end tag token does not - match the tag name of the current node, this is a - parse error. */ - // k - - /* Pop all the nodes from the current node up to - node, including node, then stop this algorithm. */ - for($x = count($this->stack) - $n; $x >= $n; $x--) { - array_pop($this->stack); - } - - } else { - $category = $this->getElementCategory($node); - - if($category !== self::SPECIAL && $category !== self::SCOPING) { - /* Otherwise, if node is in neither the formatting - category nor the phrasing category, then this is a - parse error. Stop this algorithm. The end tag token - is ignored. */ - return false; - } - } - } - break; - } - break; - } - } - - private function inTable($token) { - $clear = array('html', 'table'); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "caption" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'caption') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - /* Insert an HTML element for the token, then switch the - insertion mode to "in caption". */ - $this->insertElement($token); - $this->mode = self::IN_CAPTION; - - /* A start tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'colgroup') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the - insertion mode to "in column group". */ - $this->insertElement($token); - $this->mode = self::IN_CGROUP; - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'col') { - $this->inTable(array( - 'name' => 'colgroup', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - $this->inColumnGroup($token); - - /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('tbody', 'tfoot', 'thead'))) { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in table body". */ - $this->insertElement($token); - $this->mode = self::IN_TBODY; - - /* A start tag whose tag name is one of: "td", "th", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && - in_array($token['name'], array('td', 'th', 'tr'))) { - /* Act as if a start tag token with the tag name "tbody" had been - seen, then reprocess the current token. */ - $this->inTable(array( - 'name' => 'tbody', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inTableBody($token); - - /* A start tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'table') { - /* Parse error. Act as if an end tag token with the tag name "table" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inTable(array( - 'name' => 'table', - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - - /* An end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - return false; - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a table element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a table element has been - popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'table') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td', - 'tfoot', 'th', 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Parse error. Process the token as if the insertion mode was "in - body", with the following exception: */ - - /* If the current node is a table, tbody, tfoot, thead, or tr - element, then, whenever a node would be inserted into the current - node, it must instead be inserted into the foster parent element. */ - if(in_array(end($this->stack)->nodeName, - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* The foster parent element is the parent element of the last - table element in the stack of open elements, if there is a - table element and it has such a parent element. If there is no - table element in the stack of open elements (innerHTML case), - then the foster parent element is the first element in the - stack of open elements (the html element). Otherwise, if there - is a table element in the stack of open elements, but the last - table element in the stack of open elements has no parent, or - its parent node is not an element, then the foster parent - element is the element before the last table element in the - stack of open elements. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table') { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $table->parentNode !== null) { - $this->foster_parent = $table->parentNode; - - } elseif(!isset($table)) { - $this->foster_parent = $this->stack[0]; - - } elseif(isset($table) && ($table->parentNode === null || - $table->parentNode->nodeType !== XML_ELEMENT_NODE)) { - $this->foster_parent = $this->stack[$n - 1]; - } - } - - $this->inBody($token); - } - } - - private function inCaption($token) { - /* An end tag whose tag name is "caption" */ - if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a caption element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a caption element has - been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === 'caption') { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag - name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table')) { - /* Parse error. Act as if an end tag with the tag name "caption" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inCaption(array( - 'name' => 'caption', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - - /* An end tag whose tag name is one of: "body", "col", "colgroup", - "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th', - 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inColumnGroup($token) { - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { - /* Insert a col element for the token. Immediately pop the current - node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - /* An end tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'colgroup') { - /* If the current node is the root html element, then this is a - parse error, ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - /* Otherwise, pop the current node (which will be a colgroup - element) from the stack of open elements. Switch the insertion - mode to "in table". */ - } else { - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* An end tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Act as if an end tag with the tag name "colgroup" had been seen, - and then, if that token wasn't ignored, reprocess the current token. */ - $this->inColumnGroup(array( - 'name' => 'colgroup', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - } - } - - private function inTableBody($token) { - $clear = array('tbody', 'tfoot', 'thead', 'html'); - - /* A start tag whose tag name is "tr" */ - if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Insert a tr element for the token, then switch the insertion - mode to "in row". */ - $this->insertElement($token); - $this->mode = self::IN_ROW; - - /* A start tag whose tag name is one of: "th", "td" */ - } elseif($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Parse error. Act as if a start tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inTableBody(array( - 'name' => 'tr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inRow($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node from the stack of open elements. Switch - the insertion mode to "in table". */ - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) || - ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) { - /* If the stack of open elements does not have a tbody, thead, or - tfoot element in table scope, this is a parse error. Ignore the - token. (innerHTML case) */ - if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Act as if an end tag with the same tag name as the current - node ("tbody", "tfoot", or "thead") had been seen, then - reprocess the current token. */ - $this->inTableBody(array( - 'name' => end($this->stack)->nodeName, - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inRow($token) { - $clear = array('tr', 'html'); - - /* A start tag whose tag name is one of: "th", "td" */ - if($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in cell". */ - $this->insertElement($token); - $this->mode = self::IN_CELL; - - /* Insert a marker at the end of the list of active formatting - elements. */ - $this->a_formatting[] = self::MARKER; - - /* An end tag whose tag name is "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node (which will be a tr element) from the - stack of open elements. Switch the insertion mode to "in table - body". */ - array_pop($this->stack); - $this->mode = self::IN_TBODY; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* Act as if an end tag with the tag name "tr" had been seen, then, - if that token wasn't ignored, reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Otherwise, act as if an end tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inCell($token) { - /* An end tag whose tag name is one of: "td", "th" */ - if($token['type'] === HTML5::ENDTAG && - ($token['name'] === 'td' || $token['name'] === 'th')) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token, then this is a - parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Generate implied end tags, except for elements with the same - tag name as the token. */ - $this->generateImpliedEndTags(array($token['name'])); - - /* Now, if the current node is not an element with the same tag - name as the token, then this is a parse error. */ - // k - - /* Pop elements from this stack until an element with the same - tag name as the token has been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === $token['name']) { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in row". (The current node - will be a tr element at this point.) */ - $this->mode = self::IN_ROW; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html'))) { - /* Parse error. Ignore the token. */ - - /* An end tag whose tag name is one of: "table", "tbody", "tfoot", - "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token (which can only - happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), - then this is a parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inSelect($token) { - /* Handle the token as follows: */ - - /* A character token */ - if($token['type'] === HTML5::CHARACTR) { - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'option') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* A start tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'optgroup') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, act as if an end tag - with the tag name "optgroup" had been seen. */ - if(end($this->stack)->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'optgroup', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* An end tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'optgroup') { - /* First, if the current node is an option element, and the node - immediately before it in the stack of open elements is an optgroup - element, then act as if an end tag with the tag name "option" had - been seen. */ - $elements_in_stack = count($this->stack); - - if($this->stack[$elements_in_stack - 1]->nodeName === 'option' && - $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if($this->stack[$elements_in_stack - 1] === 'optgroup') { - array_pop($this->stack); - } - - /* An end tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'option') { - /* If the current node is an option element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if(end($this->stack)->nodeName === 'option') { - array_pop($this->stack); - } - - /* An end tag whose tag name is "select" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'select') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // w/e - - /* Otherwise: */ - } else { - /* Pop elements from the stack of open elements until a select - element has been popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'select') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* A start tag whose tag name is "select" */ - } elseif($token['name'] === 'select' && - $token['type'] === HTML5::STARTTAG) { - /* Parse error. Act as if the token had been an end tag with the - tag name "select" instead. */ - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - /* An end tag whose tag name is one of: "caption", "table", "tbody", - "tfoot", "thead", "tr", "td", "th" */ - } elseif(in_array($token['name'], array('caption', 'table', 'tbody', - 'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) { - /* Parse error. */ - // w/e - - /* If the stack of open elements has an element in table scope with - the same tag name as that of the token, then act as if an end tag - with the tag name "select" had been seen, and reprocess the token. - Otherwise, ignore the token. */ - if($this->elementInScope($token['name'], true)) { - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - $this->mainPhase($token); - } - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterBody($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed if the insertion mode - was "in body". */ - $this->inBody($token); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the first element in the stack of open - elements (the html element), with the data attribute set to the - data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->stack[0]->appendChild($comment); - - /* An end tag with the tag name "html" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { - /* If the parser was originally created in order to handle the - setting of an element's innerHTML attribute, this is a parse error; - ignore the token. (The element will be an html element in this - case.) (innerHTML case) */ - - /* Otherwise, switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* Anything else */ - } else { - /* Parse error. Set the insertion mode to "in body" and reprocess - the token. */ - $this->mode = self::IN_BODY; - return $this->inBody($token); - } - } - - private function inFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::STARTTAG) { - $this->insertElement($token); - - /* An end tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::ENDTAG) { - /* If the current node is the root html element, then this is a - parse error; ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - } else { - /* Otherwise, pop the current node from the stack of open - elements. */ - array_pop($this->stack); - - /* If the parser was not originally created in order to handle - the setting of an element's innerHTML attribute (innerHTML case), - and the current node is no longer a frameset element, then change - the insertion mode to "after frameset". */ - $this->mode = self::AFTR_FRAME; - } - - /* A start tag with the tag name "frame" */ - } elseif($token['name'] === 'frame' && - $token['type'] === HTML5::STARTTAG) { - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* An end tag with the tag name "html" */ - } elseif($token['name'] === 'html' && - $token['type'] === HTML5::ENDTAG) { - /* Switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function trailingEndPhase($token) { - /* After the main phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed in the main phase. */ - $this->mainPhase($token); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or a start tag token. Or an end tag token. */ - } elseif(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) { - /* Parse error. Switch back to the main phase and reprocess the - token. */ - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* OMG DONE!! */ - } - } - - private function insertElement($token, $append = true, $check = false) { - // Proprietary workaround for libxml2's limitations with tag names - if ($check) { - // Slightly modified HTML5 tag-name modification, - // removing anything that's not an ASCII letter, digit, or hyphen - $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); - // Remove leading hyphens and numbers - $token['name'] = ltrim($token['name'], '-0..9'); - // In theory, this should ever be needed, but just in case - if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice - } - - $el = $this->dom->createElement($token['name']); - - foreach($token['attr'] as $attr) { - if(!$el->hasAttribute($attr['name'])) { - $el->setAttribute($attr['name'], $attr['value']); - } - } - - $this->appendToRealParent($el); - $this->stack[] = $el; - - return $el; - } - - private function insertText($data) { - $text = $this->dom->createTextNode($data); - $this->appendToRealParent($text); - } - - private function insertComment($data) { - $comment = $this->dom->createComment($data); - $this->appendToRealParent($comment); - } - - private function appendToRealParent($node) { - if($this->foster_parent === null) { - end($this->stack)->appendChild($node); - - } elseif($this->foster_parent !== null) { - /* If the foster parent element is the parent element of the - last table element in the stack of open elements, then the new - node must be inserted immediately before the last table element - in the stack of open elements in the foster parent element; - otherwise, the new node must be appended to the foster parent - element. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table' && - $this->stack[$n]->parentNode !== null) { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $this->foster_parent->isSameNode($table->parentNode)) - $this->foster_parent->insertBefore($node, $table); - else - $this->foster_parent->appendChild($node); - - $this->foster_parent = null; - } - } - - private function elementInScope($el, $table = false) { - if(is_array($el)) { - foreach($el as $element) { - if($this->elementInScope($element, $table)) { - return true; - } - } - - return false; - } - - $leng = count($this->stack); - - for($n = 0; $n < $leng; $n++) { - /* 1. Initialise node to be the current node (the bottommost node of - the stack). */ - $node = $this->stack[$leng - 1 - $n]; - - if($node->tagName === $el) { - /* 2. If node is the target node, terminate in a match state. */ - return true; - - } elseif($node->tagName === 'table') { - /* 3. Otherwise, if node is a table element, terminate in a failure - state. */ - return false; - - } elseif($table === true && in_array($node->tagName, array('caption', 'td', - 'th', 'button', 'marquee', 'object'))) { - /* 4. Otherwise, if the algorithm is the "has an element in scope" - variant (rather than the "has an element in table scope" variant), - and node is one of the following, terminate in a failure state. */ - return false; - - } elseif($node === $node->ownerDocument->documentElement) { - /* 5. Otherwise, if node is an html element (root element), terminate - in a failure state. (This can only happen if the node is the topmost - node of the stack of open elements, and prevents the next step from - being invoked if there are no more elements in the stack.) */ - return false; - } - - /* Otherwise, set node to the previous entry in the stack of open - elements and return to step 2. (This will never fail, since the loop - will always terminate in the previous step if the top of the stack - is reached.) */ - } - } - - private function reconstructActiveFormattingElements() { - /* 1. If there are no entries in the list of active formatting elements, - then there is nothing to reconstruct; stop this algorithm. */ - $formatting_elements = count($this->a_formatting); - - if($formatting_elements === 0) { - return false; - } - - /* 3. Let entry be the last (most recently added) element in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. If the last (most recently added) entry in the list of active - formatting elements is a marker, or if it is an element that is in the - stack of open elements, then there is nothing to reconstruct; stop this - algorithm. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - return false; - } - - for($a = $formatting_elements - 1; $a >= 0; true) { - /* 4. If there are no entries before entry in the list of active - formatting elements, then jump to step 8. */ - if($a === 0) { - $step_seven = false; - break; - } - - /* 5. Let entry be the entry one earlier than entry in the list of - active formatting elements. */ - $a--; - $entry = $this->a_formatting[$a]; - - /* 6. If entry is neither a marker nor an element that is also in - thetack of open elements, go to step 4. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - break; - } - } - - while(true) { - /* 7. Let entry be the element one later than entry in the list of - active formatting elements. */ - if(isset($step_seven) && $step_seven === true) { - $a++; - $entry = $this->a_formatting[$a]; - } - - /* 8. Perform a shallow clone of the element entry to obtain clone. */ - $clone = $entry->cloneNode(); - - /* 9. Append clone to the current node and push it onto the stack - of open elements so that it is the new current node. */ - end($this->stack)->appendChild($clone); - $this->stack[] = $clone; - - /* 10. Replace the entry for entry in the list with an entry for - clone. */ - $this->a_formatting[$a] = $clone; - - /* 11. If the entry for clone in the list of active formatting - elements is not the last entry in the list, return to step 7. */ - if(end($this->a_formatting) !== $clone) { - $step_seven = true; - } else { - break; - } - } - } - - private function clearTheActiveFormattingElementsUpToTheLastMarker() { - /* When the steps below require the UA to clear the list of active - formatting elements up to the last marker, the UA must perform the - following steps: */ - - while(true) { - /* 1. Let entry be the last (most recently added) entry in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. Remove entry from the list of active formatting elements. */ - array_pop($this->a_formatting); - - /* 3. If entry was a marker, then stop the algorithm at this point. - The list has been cleared up to the last marker. */ - if($entry === self::MARKER) { - break; - } - } - } - - private function generateImpliedEndTags($exclude = array()) { - /* When the steps below require the UA to generate implied end tags, - then, if the current node is a dd element, a dt element, an li element, - a p element, a td element, a th element, or a tr element, the UA must - act as if an end tag with the respective tag name had been seen and - then generate implied end tags again. */ - $node = end($this->stack); - $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); - - while(in_array(end($this->stack)->nodeName, $elements)) { - array_pop($this->stack); - } - } - - private function getElementCategory($node) { - $name = $node->tagName; - if(in_array($name, $this->special)) - return self::SPECIAL; - - elseif(in_array($name, $this->scoping)) - return self::SCOPING; - - elseif(in_array($name, $this->formatting)) - return self::FORMATTING; - - else - return self::PHRASING; - } - - private function clearStackToTableContext($elements) { - /* When the steps above require the UA to clear the stack back to a - table context, it means that the UA must, while the current node is not - a table element or an html element, pop elements from the stack of open - elements. If this causes any elements to be popped from the stack, then - this is a parse error. */ - while(true) { - $node = end($this->stack)->nodeName; - - if(in_array($node, $elements)) { - break; - } else { - array_pop($this->stack); - } - } - } - - private function resetInsertionMode() { - /* 1. Let last be false. */ - $last = false; - $leng = count($this->stack); - - for($n = $leng - 1; $n >= 0; $n--) { - /* 2. Let node be the last node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 3. If node is the first node in the stack of open elements, then - set last to true. If the element whose innerHTML attribute is being - set is neither a td element nor a th element, then set node to the - element whose innerHTML attribute is being set. (innerHTML case) */ - if($this->stack[0]->isSameNode($node)) { - $last = true; - } - - /* 4. If node is a select element, then switch the insertion mode to - "in select" and abort these steps. (innerHTML case) */ - if($node->nodeName === 'select') { - $this->mode = self::IN_SELECT; - break; - - /* 5. If node is a td or th element, then switch the insertion mode - to "in cell" and abort these steps. */ - } elseif($node->nodeName === 'td' || $node->nodeName === 'th') { - $this->mode = self::IN_CELL; - break; - - /* 6. If node is a tr element, then switch the insertion mode to - "in row" and abort these steps. */ - } elseif($node->nodeName === 'tr') { - $this->mode = self::IN_ROW; - break; - - /* 7. If node is a tbody, thead, or tfoot element, then switch the - insertion mode to "in table body" and abort these steps. */ - } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { - $this->mode = self::IN_TBODY; - break; - - /* 8. If node is a caption element, then switch the insertion mode - to "in caption" and abort these steps. */ - } elseif($node->nodeName === 'caption') { - $this->mode = self::IN_CAPTION; - break; - - /* 9. If node is a colgroup element, then switch the insertion mode - to "in column group" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'colgroup') { - $this->mode = self::IN_CGROUP; - break; - - /* 10. If node is a table element, then switch the insertion mode - to "in table" and abort these steps. */ - } elseif($node->nodeName === 'table') { - $this->mode = self::IN_TABLE; - break; - - /* 11. If node is a head element, then switch the insertion mode - to "in body" ("in body"! not "in head"!) and abort these steps. - (innerHTML case) */ - } elseif($node->nodeName === 'head') { - $this->mode = self::IN_BODY; - break; - - /* 12. If node is a body element, then switch the insertion mode to - "in body" and abort these steps. */ - } elseif($node->nodeName === 'body') { - $this->mode = self::IN_BODY; - break; - - /* 13. If node is a frameset element, then switch the insertion - mode to "in frameset" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'frameset') { - $this->mode = self::IN_FRAME; - break; - - /* 14. If node is an html element, then: if the head element - pointer is null, switch the insertion mode to "before head", - otherwise, switch the insertion mode to "after head". In either - case, abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'html') { - $this->mode = ($this->head_pointer === null) - ? self::BEFOR_HEAD - : self::AFTER_HEAD; - - break; - - /* 15. If last is true, then set the insertion mode to "in body" - and abort these steps. (innerHTML case) */ - } elseif($last) { - $this->mode = self::IN_BODY; - break; - } - } - } - - private function closeCell() { - /* If the stack of open elements has a td or th element in table scope, - then act as if an end tag token with that tag name had been seen. */ - foreach(array('td', 'th') as $cell) { - if($this->elementInScope($cell, true)) { - $this->inCell(array( - 'name' => $cell, - 'type' => HTML5::ENDTAG - )); - - break; - } - } - } - - public function save() { - return $this->dom; - } -} - diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PercentEncoder.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PercentEncoder.php deleted file mode 100644 index a8ad230d..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PercentEncoder.php +++ /dev/null @@ -1,98 +0,0 @@ -preserve[$i] = true; // digits - for ($i = 65; $i <= 90; $i++) $this->preserve[$i] = true; // upper-case - for ($i = 97; $i <= 122; $i++) $this->preserve[$i] = true; // lower-case - $this->preserve[45] = true; // Dash - - $this->preserve[46] = true; // Period . - $this->preserve[95] = true; // Underscore _ - $this->preserve[126]= true; // Tilde ~ - - // extra letters not to escape - if ($preserve !== false) { - for ($i = 0, $c = strlen($preserve); $i < $c; $i++) { - $this->preserve[ord($preserve[$i])] = true; - } - } - } - - /** - * Our replacement for urlencode, it encodes all non-reserved characters, - * as well as any extra characters that were instructed to be preserved. - * @note - * Assumes that the string has already been normalized, making any - * and all percent escape sequences valid. Percents will not be - * re-escaped, regardless of their status in $preserve - * @param $string String to be encoded - * @return Encoded string. - */ - public function encode($string) { - $ret = ''; - for ($i = 0, $c = strlen($string); $i < $c; $i++) { - if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])]) ) { - $ret .= '%' . sprintf('%02X', $int); - } else { - $ret .= $string[$i]; - } - } - return $ret; - } - - /** - * Fix up percent-encoding by decoding unreserved characters and normalizing. - * @warning This function is affected by $preserve, even though the - * usual desired behavior is for this not to preserve those - * characters. Be careful when reusing instances of PercentEncoder! - * @param $string String to normalize - */ - public function normalize($string) { - if ($string == '') return ''; - $parts = explode('%', $string); - $ret = array_shift($parts); - foreach ($parts as $part) { - $length = strlen($part); - if ($length < 2) { - $ret .= '%25' . $part; - continue; - } - $encoding = substr($part, 0, 2); - $text = substr($part, 2); - if (!ctype_xdigit($encoding)) { - $ret .= '%25' . $part; - continue; - } - $int = hexdec($encoding); - if (isset($this->preserve[$int])) { - $ret .= chr($int) . $text; - continue; - } - $encoding = strtoupper($encoding); - $ret .= '%' . $encoding . $text; - } - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer.php deleted file mode 100644 index a0d4a0fd..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer.php +++ /dev/null @@ -1,176 +0,0 @@ -getAll(); - $context = new HTMLPurifier_Context(); - $this->generator = new HTMLPurifier_Generator($config, $context); - } - - /** - * Main function that renders object or aspect of that object - * @note Parameters vary depending on printer - */ - // function render() {} - - /** - * Returns a start tag - * @param $tag Tag name - * @param $attr Attribute array - */ - protected function start($tag, $attr = array()) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) - ); - } - - /** - * Returns an end teg - * @param $tag Tag name - */ - protected function end($tag) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_End($tag) - ); - } - - /** - * Prints a complete element with content inside - * @param $tag Tag name - * @param $contents Element contents - * @param $attr Tag attributes - * @param $escape Bool whether or not to escape contents - */ - protected function element($tag, $contents, $attr = array(), $escape = true) { - return $this->start($tag, $attr) . - ($escape ? $this->escape($contents) : $contents) . - $this->end($tag); - } - - protected function elementEmpty($tag, $attr = array()) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_Empty($tag, $attr) - ); - } - - protected function text($text) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_Text($text) - ); - } - - /** - * Prints a simple key/value row in a table. - * @param $name Key - * @param $value Value - */ - protected function row($name, $value) { - if (is_bool($value)) $value = $value ? 'On' : 'Off'; - return - $this->start('tr') . "\n" . - $this->element('th', $name) . "\n" . - $this->element('td', $value) . "\n" . - $this->end('tr') - ; - } - - /** - * Escapes a string for HTML output. - * @param $string String to escape - */ - protected function escape($string) { - $string = HTMLPurifier_Encoder::cleanUTF8($string); - $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); - return $string; - } - - /** - * Takes a list of strings and turns them into a single list - * @param $array List of strings - * @param $polite Bool whether or not to add an end before the last - */ - protected function listify($array, $polite = false) { - if (empty($array)) return 'None'; - $ret = ''; - $i = count($array); - foreach ($array as $value) { - $i--; - $ret .= $value; - if ($i > 0 && !($polite && $i == 1)) $ret .= ', '; - if ($polite && $i == 1) $ret .= 'and '; - } - return $ret; - } - - /** - * Retrieves the class of an object without prefixes, as well as metadata - * @param $obj Object to determine class of - * @param $prefix Further prefix to remove - */ - protected function getClass($obj, $sec_prefix = '') { - static $five = null; - if ($five === null) $five = version_compare(PHP_VERSION, '5', '>='); - $prefix = 'HTMLPurifier_' . $sec_prefix; - if (!$five) $prefix = strtolower($prefix); - $class = str_replace($prefix, '', get_class($obj)); - $lclass = strtolower($class); - $class .= '('; - switch ($lclass) { - case 'enum': - $values = array(); - foreach ($obj->valid_values as $value => $bool) { - $values[] = $value; - } - $class .= implode(', ', $values); - break; - case 'css_composite': - $values = array(); - foreach ($obj->defs as $def) { - $values[] = $this->getClass($def, $sec_prefix); - } - $class .= implode(', ', $values); - break; - case 'css_multiple': - $class .= $this->getClass($obj->single, $sec_prefix) . ', '; - $class .= $obj->max; - break; - case 'css_denyelementdecorator': - $class .= $this->getClass($obj->def, $sec_prefix) . ', '; - $class .= $obj->element; - break; - case 'css_importantdecorator': - $class .= $this->getClass($obj->def, $sec_prefix); - if ($obj->allow) $class .= ', !important'; - break; - } - $class .= ')'; - return $class; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php deleted file mode 100644 index 0be17df7..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php +++ /dev/null @@ -1,38 +0,0 @@ -def = $config->getCSSDefinition(); - $ret = ''; - - $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); - $ret .= $this->start('table'); - - $ret .= $this->element('caption', 'Properties ($info)'); - - $ret .= $this->start('thead'); - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Property', array('class' => 'heavy')); - $ret .= $this->element('th', 'Definition', array('class' => 'heavy', 'style' => 'width:auto;')); - $ret .= $this->end('tr'); - $ret .= $this->end('thead'); - - ksort($this->def->info); - foreach ($this->def->info as $property => $obj) { - $name = $this->getClass($obj, 'AttrDef_'); - $ret .= $this->row($property, $name); - } - - $ret .= $this->end('table'); - $ret .= $this->end('div'); - - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css deleted file mode 100644 index 3ff1a88a..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css +++ /dev/null @@ -1,10 +0,0 @@ - -.hp-config {} - -.hp-config tbody th {text-align:right; padding-right:0.5em;} -.hp-config thead, .hp-config .namespace {background:#3C578C; color:#FFF;} -.hp-config .namespace th {text-align:center;} -.hp-config .verbose {display:none;} -.hp-config .controls {text-align:center;} - -/* vim: et sw=4 sts=4 */ diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js deleted file mode 100644 index cba00c9b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js +++ /dev/null @@ -1,5 +0,0 @@ -function toggleWriteability(id_of_patient, checked) { - document.getElementById(id_of_patient).disabled = checked; -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php deleted file mode 100644 index 4d391992..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php +++ /dev/null @@ -1,368 +0,0 @@ -docURL = $doc_url; - $this->name = $name; - $this->compress = $compress; - // initialize sub-printers - $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); - $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); - } - - /** - * Sets default column and row size for textareas in sub-printers - * @param $cols Integer columns of textarea, null to use default - * @param $rows Integer rows of textarea, null to use default - */ - public function setTextareaDimensions($cols = null, $rows = null) { - if ($cols) $this->fields['default']->cols = $cols; - if ($rows) $this->fields['default']->rows = $rows; - } - - /** - * Retrieves styling, in case it is not accessible by webserver - */ - public static function getCSS() { - return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); - } - - /** - * Retrieves JavaScript, in case it is not accessible by webserver - */ - public static function getJavaScript() { - return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); - } - - /** - * Returns HTML output for a configuration form - * @param $config Configuration object of current form state, or an array - * where [0] has an HTML namespace and [1] is being rendered. - * @param $allowed Optional namespace(s) and directives to restrict form to. - */ - public function render($config, $allowed = true, $render_controls = true) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - - $this->config = $config; - $this->genConfig = $gen_config; - $this->prepareGenerator($gen_config); - - $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); - $all = array(); - foreach ($allowed as $key) { - list($ns, $directive) = $key; - $all[$ns][$directive] = $config->get($ns .'.'. $directive); - } - - $ret = ''; - $ret .= $this->start('table', array('class' => 'hp-config')); - $ret .= $this->start('thead'); - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); - $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); - $ret .= $this->end('tr'); - $ret .= $this->end('thead'); - foreach ($all as $ns => $directives) { - $ret .= $this->renderNamespace($ns, $directives); - } - if ($render_controls) { - $ret .= $this->start('tbody'); - $ret .= $this->start('tr'); - $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); - $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); - $ret .= '[Reset]'; - $ret .= $this->end('td'); - $ret .= $this->end('tr'); - $ret .= $this->end('tbody'); - } - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders a single namespace - * @param $ns String namespace name - * @param $directive Associative array of directives to values - */ - protected function renderNamespace($ns, $directives) { - $ret = ''; - $ret .= $this->start('tbody', array('class' => 'namespace')); - $ret .= $this->start('tr'); - $ret .= $this->element('th', $ns, array('colspan' => 2)); - $ret .= $this->end('tr'); - $ret .= $this->end('tbody'); - $ret .= $this->start('tbody'); - foreach ($directives as $directive => $value) { - $ret .= $this->start('tr'); - $ret .= $this->start('th'); - if ($this->docURL) { - $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); - $ret .= $this->start('a', array('href' => $url)); - } - $attr = array('for' => "{$this->name}:$ns.$directive"); - - // crop directive name if it's too long - if (!$this->compress || (strlen($directive) < $this->compress)) { - $directive_disp = $directive; - } else { - $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; - $attr['title'] = $directive; - } - - $ret .= $this->element( - 'label', - $directive_disp, - // component printers must create an element with this id - $attr - ); - if ($this->docURL) $ret .= $this->end('a'); - $ret .= $this->end('th'); - - $ret .= $this->start('td'); - $def = $this->config->def->info["$ns.$directive"]; - if (is_int($def)) { - $allow_null = $def < 0; - $type = abs($def); - } else { - $type = $def->type; - $allow_null = isset($def->allow_null); - } - if (!isset($this->fields[$type])) $type = 0; // default - $type_obj = $this->fields[$type]; - if ($allow_null) { - $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); - } - $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); - $ret .= $this->end('td'); - $ret .= $this->end('tr'); - } - $ret .= $this->end('tbody'); - return $ret; - } - -} - -/** - * Printer decorator for directives that accept null - */ -class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer { - /** - * Printer being decorated - */ - protected $obj; - /** - * @param $obj Printer to decorate - */ - public function __construct($obj) { - parent::__construct(); - $this->obj = $obj; - } - public function render($ns, $directive, $value, $name, $config) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - $this->prepareGenerator($gen_config); - - $ret = ''; - $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); - $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); - $ret .= $this->text(' Null/Disabled'); - $ret .= $this->end('label'); - $attr = array( - 'type' => 'checkbox', - 'value' => '1', - 'class' => 'null-toggle', - 'name' => "$name"."[Null_$ns.$directive]", - 'id' => "$name:Null_$ns.$directive", - 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! - ); - if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { - // modify inline javascript slightly - $attr['onclick'] = "toggleWriteability('$name:Yes_$ns.$directive',checked);toggleWriteability('$name:No_$ns.$directive',checked)"; - } - if ($value === null) $attr['checked'] = 'checked'; - $ret .= $this->elementEmpty('input', $attr); - $ret .= $this->text(' or '); - $ret .= $this->elementEmpty('br'); - $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); - return $ret; - } -} - -/** - * Swiss-army knife configuration form field printer - */ -class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { - public $cols = 18; - public $rows = 5; - public function render($ns, $directive, $value, $name, $config) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - $this->prepareGenerator($gen_config); - // this should probably be split up a little - $ret = ''; - $def = $config->def->info["$ns.$directive"]; - if (is_int($def)) { - $type = abs($def); - } else { - $type = $def->type; - } - if (is_array($value)) { - switch ($type) { - case HTMLPurifier_VarParser::LOOKUP: - $array = $value; - $value = array(); - foreach ($array as $val => $b) { - $value[] = $val; - } - case HTMLPurifier_VarParser::ALIST: - $value = implode(PHP_EOL, $value); - break; - case HTMLPurifier_VarParser::HASH: - $nvalue = ''; - foreach ($value as $i => $v) { - $nvalue .= "$i:$v" . PHP_EOL; - } - $value = $nvalue; - break; - default: - $value = ''; - } - } - if ($type === HTMLPurifier_VarParser::MIXED) { - return 'Not supported'; - $value = serialize($value); - } - $attr = array( - 'name' => "$name"."[$ns.$directive]", - 'id' => "$name:$ns.$directive" - ); - if ($value === null) $attr['disabled'] = 'disabled'; - if (isset($def->allowed)) { - $ret .= $this->start('select', $attr); - foreach ($def->allowed as $val => $b) { - $attr = array(); - if ($value == $val) $attr['selected'] = 'selected'; - $ret .= $this->element('option', $val, $attr); - } - $ret .= $this->end('select'); - } elseif ( - $type === HTMLPurifier_VarParser::TEXT || - $type === HTMLPurifier_VarParser::ITEXT || - $type === HTMLPurifier_VarParser::ALIST || - $type === HTMLPurifier_VarParser::HASH || - $type === HTMLPurifier_VarParser::LOOKUP - ) { - $attr['cols'] = $this->cols; - $attr['rows'] = $this->rows; - $ret .= $this->start('textarea', $attr); - $ret .= $this->text($value); - $ret .= $this->end('textarea'); - } else { - $attr['value'] = $value; - $attr['type'] = 'text'; - $ret .= $this->elementEmpty('input', $attr); - } - return $ret; - } -} - -/** - * Bool form field printer - */ -class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { - public function render($ns, $directive, $value, $name, $config) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - $this->prepareGenerator($gen_config); - $ret = ''; - $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); - - $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); - $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); - $ret .= $this->text(' Yes'); - $ret .= $this->end('label'); - - $attr = array( - 'type' => 'radio', - 'name' => "$name"."[$ns.$directive]", - 'id' => "$name:Yes_$ns.$directive", - 'value' => '1' - ); - if ($value === true) $attr['checked'] = 'checked'; - if ($value === null) $attr['disabled'] = 'disabled'; - $ret .= $this->elementEmpty('input', $attr); - - $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); - $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); - $ret .= $this->text(' No'); - $ret .= $this->end('label'); - - $attr = array( - 'type' => 'radio', - 'name' => "$name"."[$ns.$directive]", - 'id' => "$name:No_$ns.$directive", - 'value' => '0' - ); - if ($value === false) $attr['checked'] = 'checked'; - if ($value === null) $attr['disabled'] = 'disabled'; - $ret .= $this->elementEmpty('input', $attr); - - $ret .= $this->end('div'); - - return $ret; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php deleted file mode 100644 index 556caf57..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php +++ /dev/null @@ -1,272 +0,0 @@ -config =& $config; - - $this->def = $config->getHTMLDefinition(); - - $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); - - $ret .= $this->renderDoctype(); - $ret .= $this->renderEnvironment(); - $ret .= $this->renderContentSets(); - $ret .= $this->renderInfo(); - - $ret .= $this->end('div'); - - return $ret; - } - - /** - * Renders the Doctype table - */ - protected function renderDoctype() { - $doctype = $this->def->doctype; - $ret = ''; - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Doctype'); - $ret .= $this->row('Name', $doctype->name); - $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No'); - $ret .= $this->row('Default Modules', implode($doctype->modules, ', ')); - $ret .= $this->row('Default Tidy Modules', implode($doctype->tidyModules, ', ')); - $ret .= $this->end('table'); - return $ret; - } - - - /** - * Renders environment table, which is miscellaneous info - */ - protected function renderEnvironment() { - $def = $this->def; - - $ret = ''; - - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Environment'); - - $ret .= $this->row('Parent of fragment', $def->info_parent); - $ret .= $this->renderChildren($def->info_parent_def->child); - $ret .= $this->row('Block wrap name', $def->info_block_wrapper); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Global attributes'); - $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr),0,0); - $ret .= $this->end('tr'); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Tag transforms'); - $list = array(); - foreach ($def->info_tag_transform as $old => $new) { - $new = $this->getClass($new, 'TagTransform_'); - $list[] = "<$old> with $new"; - } - $ret .= $this->element('td', $this->listify($list)); - $ret .= $this->end('tr'); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Pre-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); - $ret .= $this->end('tr'); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Post-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); - $ret .= $this->end('tr'); - - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders the Content Sets table - */ - protected function renderContentSets() { - $ret = ''; - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Content Sets'); - foreach ($this->def->info_content_sets as $name => $lookup) { - $ret .= $this->heavyHeader($name); - $ret .= $this->start('tr'); - $ret .= $this->element('td', $this->listifyTagLookup($lookup)); - $ret .= $this->end('tr'); - } - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders the Elements ($info) table - */ - protected function renderInfo() { - $ret = ''; - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Elements ($info)'); - ksort($this->def->info); - $ret .= $this->heavyHeader('Allowed tags', 2); - $ret .= $this->start('tr'); - $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2)); - $ret .= $this->end('tr'); - foreach ($this->def->info as $name => $def) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', "<$name>", array('class'=>'heavy', 'colspan' => 2)); - $ret .= $this->end('tr'); - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Inline content'); - $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); - $ret .= $this->end('tr'); - if (!empty($def->excludes)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Excludes'); - $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); - $ret .= $this->end('tr'); - } - if (!empty($def->attr_transform_pre)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Pre-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); - $ret .= $this->end('tr'); - } - if (!empty($def->attr_transform_post)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Post-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); - $ret .= $this->end('tr'); - } - if (!empty($def->auto_close)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Auto closed by'); - $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); - $ret .= $this->end('tr'); - } - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Allowed attributes'); - $ret .= $this->element('td',$this->listifyAttr($def->attr), array(), 0); - $ret .= $this->end('tr'); - - if (!empty($def->required_attr)) { - $ret .= $this->row('Required attributes', $this->listify($def->required_attr)); - } - - $ret .= $this->renderChildren($def->child); - } - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders a row describing the allowed children of an element - * @param $def HTMLPurifier_ChildDef of pertinent element - */ - protected function renderChildren($def) { - $context = new HTMLPurifier_Context(); - $ret = ''; - $ret .= $this->start('tr'); - $elements = array(); - $attr = array(); - if (isset($def->elements)) { - if ($def->type == 'strictblockquote') { - $def->validateChildren(array(), $this->config, $context); - } - $elements = $def->elements; - } - if ($def->type == 'chameleon') { - $attr['rowspan'] = 2; - } elseif ($def->type == 'empty') { - $elements = array(); - } elseif ($def->type == 'table') { - $elements = array_flip(array('col', 'caption', 'colgroup', 'thead', - 'tfoot', 'tbody', 'tr')); - } - $ret .= $this->element('th', 'Allowed children', $attr); - - if ($def->type == 'chameleon') { - - $ret .= $this->element('td', - 'Block: ' . - $this->escape($this->listifyTagLookup($def->block->elements)),0,0); - $ret .= $this->end('tr'); - $ret .= $this->start('tr'); - $ret .= $this->element('td', - 'Inline: ' . - $this->escape($this->listifyTagLookup($def->inline->elements)),0,0); - - } elseif ($def->type == 'custom') { - - $ret .= $this->element('td', ''.ucfirst($def->type).': ' . - $def->dtd_regex); - - } else { - $ret .= $this->element('td', - ''.ucfirst($def->type).': ' . - $this->escape($this->listifyTagLookup($elements)),0,0); - } - $ret .= $this->end('tr'); - return $ret; - } - - /** - * Listifies a tag lookup table. - * @param $array Tag lookup array in form of array('tagname' => true) - */ - protected function listifyTagLookup($array) { - ksort($array); - $list = array(); - foreach ($array as $name => $discard) { - if ($name !== '#PCDATA' && !isset($this->def->info[$name])) continue; - $list[] = $name; - } - return $this->listify($list); - } - - /** - * Listifies a list of objects by retrieving class names and internal state - * @param $array List of objects - * @todo Also add information about internal state - */ - protected function listifyObjectList($array) { - ksort($array); - $list = array(); - foreach ($array as $discard => $obj) { - $list[] = $this->getClass($obj, 'AttrTransform_'); - } - return $this->listify($list); - } - - /** - * Listifies a hash of attributes to AttrDef classes - * @param $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) - */ - protected function listifyAttr($array) { - ksort($array); - $list = array(); - foreach ($array as $name => $obj) { - if ($obj === false) continue; - $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; - } - return $this->listify($list); - } - - /** - * Creates a heavy header row - */ - protected function heavyHeader($text, $num = 1) { - $ret = ''; - $ret .= $this->start('tr'); - $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); - $ret .= $this->end('tr'); - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyList.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyList.php deleted file mode 100644 index f3e2947c..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyList.php +++ /dev/null @@ -1,86 +0,0 @@ -parent = $parent; - } - - /** - * Recursively retrieves the value for a key - */ - public function get($name) { - if ($this->has($name)) return $this->data[$name]; - // possible performance bottleneck, convert to iterative if necessary - if ($this->parent) return $this->parent->get($name); - throw new HTMLPurifier_Exception("Key '$name' not found"); - } - - /** - * Sets the value of a key, for this plist - */ - public function set($name, $value) { - $this->data[$name] = $value; - } - - /** - * Returns true if a given key exists - */ - public function has($name) { - return array_key_exists($name, $this->data); - } - - /** - * Resets a value to the value of it's parent, usually the default. If - * no value is specified, the entire plist is reset. - */ - public function reset($name = null) { - if ($name == null) $this->data = array(); - else unset($this->data[$name]); - } - - /** - * Squashes this property list and all of its property lists into a single - * array, and returns the array. This value is cached by default. - * @param $force If true, ignores the cache and regenerates the array. - */ - public function squash($force = false) { - if ($this->cache !== null && !$force) return $this->cache; - if ($this->parent) { - return $this->cache = array_merge($this->parent->squash($force), $this->data); - } else { - return $this->cache = $this->data; - } - } - - /** - * Returns the parent plist. - */ - public function getParent() { - return $this->parent; - } - - /** - * Sets the parent plist. - */ - public function setParent($plist) { - $this->parent = $plist; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php deleted file mode 100644 index 7fa2088e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php +++ /dev/null @@ -1,32 +0,0 @@ -l = strlen($filter); - $this->filter = $filter; - } - - public function accept() { - $key = $this->getInnerIterator()->key(); - if( strncmp($key, $this->filter, $this->l) !== 0 ) { - return false; - } - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy.php deleted file mode 100644 index e975e2c8..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy.php +++ /dev/null @@ -1,26 +0,0 @@ -strategies as $strategy) { - $tokens = $strategy->execute($tokens, $config, $context); - } - return $tokens; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/Core.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/Core.php deleted file mode 100644 index c7d3c79c..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/Core.php +++ /dev/null @@ -1,18 +0,0 @@ -strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); - $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); - $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); - $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php deleted file mode 100644 index dc4ef88b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php +++ /dev/null @@ -1,328 +0,0 @@ -getHTMLDefinition(); - - // insert implicit "parent" node, will be removed at end. - // DEFINITION CALL - $parent_name = $definition->info_parent; - array_unshift($tokens, new HTMLPurifier_Token_Start($parent_name)); - $tokens[] = new HTMLPurifier_Token_End($parent_name); - - // setup the context variable 'IsInline', for chameleon processing - // is 'false' when we are not inline, 'true' when it must always - // be inline, and an integer when it is inline for a certain - // branch of the document tree - $is_inline = $definition->info_parent_def->descendants_are_inline; - $context->register('IsInline', $is_inline); - - // setup error collector - $e =& $context->get('ErrorCollector', true); - - //####################################################################// - // Loop initialization - - // stack that contains the indexes of all parents, - // $stack[count($stack)-1] being the current parent - $stack = array(); - - // stack that contains all elements that are excluded - // it is organized by parent elements, similar to $stack, - // but it is only populated when an element with exclusions is - // processed, i.e. there won't be empty exclusions. - $exclude_stack = array(); - - // variable that contains the start token while we are processing - // nodes. This enables error reporting to do its job - $start_token = false; - $context->register('CurrentToken', $start_token); - - //####################################################################// - // Loop - - // iterate through all start nodes. Determining the start node - // is complicated so it has been omitted from the loop construct - for ($i = 0, $size = count($tokens) ; $i < $size; ) { - - //################################################################// - // Gather information on children - - // child token accumulator - $child_tokens = array(); - - // scroll to the end of this node, report number, and collect - // all children - for ($j = $i, $depth = 0; ; $j++) { - if ($tokens[$j] instanceof HTMLPurifier_Token_Start) { - $depth++; - // skip token assignment on first iteration, this is the - // token we currently are on - if ($depth == 1) continue; - } elseif ($tokens[$j] instanceof HTMLPurifier_Token_End) { - $depth--; - // skip token assignment on last iteration, this is the - // end token of the token we're currently on - if ($depth == 0) break; - } - $child_tokens[] = $tokens[$j]; - } - - // $i is index of start token - // $j is index of end token - - $start_token = $tokens[$i]; // to make token available via CurrentToken - - //################################################################// - // Gather information on parent - - // calculate parent information - if ($count = count($stack)) { - $parent_index = $stack[$count-1]; - $parent_name = $tokens[$parent_index]->name; - if ($parent_index == 0) { - $parent_def = $definition->info_parent_def; - } else { - $parent_def = $definition->info[$parent_name]; - } - } else { - // processing as if the parent were the "root" node - // unknown info, it won't be used anyway, in the future, - // we may want to enforce one element only (this is - // necessary for HTML Purifier to clean entire documents - $parent_index = $parent_name = $parent_def = null; - } - - // calculate context - if ($is_inline === false) { - // check if conditions make it inline - if (!empty($parent_def) && $parent_def->descendants_are_inline) { - $is_inline = $count - 1; - } - } else { - // check if we're out of inline - if ($count === $is_inline) { - $is_inline = false; - } - } - - //################################################################// - // Determine whether element is explicitly excluded SGML-style - - // determine whether or not element is excluded by checking all - // parent exclusions. The array should not be very large, two - // elements at most. - $excluded = false; - if (!empty($exclude_stack)) { - foreach ($exclude_stack as $lookup) { - if (isset($lookup[$tokens[$i]->name])) { - $excluded = true; - // no need to continue processing - break; - } - } - } - - //################################################################// - // Perform child validation - - if ($excluded) { - // there is an exclusion, remove the entire node - $result = false; - $excludes = array(); // not used, but good to initialize anyway - } else { - // DEFINITION CALL - if ($i === 0) { - // special processing for the first node - $def = $definition->info_parent_def; - } else { - $def = $definition->info[$tokens[$i]->name]; - - } - - if (!empty($def->child)) { - // have DTD child def validate children - $result = $def->child->validateChildren( - $child_tokens, $config, $context); - } else { - // weird, no child definition, get rid of everything - $result = false; - } - - // determine whether or not this element has any exclusions - $excludes = $def->excludes; - } - - // $result is now a bool or array - - //################################################################// - // Process result by interpreting $result - - if ($result === true || $child_tokens === $result) { - // leave the node as is - - // register start token as a parental node start - $stack[] = $i; - - // register exclusions if there are any - if (!empty($excludes)) $exclude_stack[] = $excludes; - - // move cursor to next possible start node - $i++; - - } elseif($result === false) { - // remove entire node - - if ($e) { - if ($excluded) { - $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); - } else { - $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); - } - } - - // calculate length of inner tokens and current tokens - $length = $j - $i + 1; - - // perform removal - array_splice($tokens, $i, $length); - - // update size - $size -= $length; - - // there is no start token to register, - // current node is now the next possible start node - // unless it turns out that we need to do a double-check - - // this is a rought heuristic that covers 100% of HTML's - // cases and 99% of all other cases. A child definition - // that would be tricked by this would be something like: - // ( | a b c) where it's all or nothing. Fortunately, - // our current implementation claims that that case would - // not allow empty, even if it did - if (!$parent_def->child->allow_empty) { - // we need to do a double-check - $i = $parent_index; - array_pop($stack); - } - - // PROJECTED OPTIMIZATION: Process all children elements before - // reprocessing parent node. - - } else { - // replace node with $result - - // calculate length of inner tokens - $length = $j - $i - 1; - - if ($e) { - if (empty($result) && $length) { - $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); - } else { - $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); - } - } - - // perform replacement - array_splice($tokens, $i + 1, $length, $result); - - // update size - $size -= $length; - $size += count($result); - - // register start token as a parental node start - $stack[] = $i; - - // register exclusions if there are any - if (!empty($excludes)) $exclude_stack[] = $excludes; - - // move cursor to next possible start node - $i++; - - } - - //################################################################// - // Scroll to next start node - - // We assume, at this point, that $i is the index of the token - // that is the first possible new start point for a node. - - // Test if the token indeed is a start tag, if not, move forward - // and test again. - $size = count($tokens); - while ($i < $size and !$tokens[$i] instanceof HTMLPurifier_Token_Start) { - if ($tokens[$i] instanceof HTMLPurifier_Token_End) { - // pop a token index off the stack if we ended a node - array_pop($stack); - // pop an exclusion lookup off exclusion stack if - // we ended node and that node had exclusions - if ($i == 0 || $i == $size - 1) { - // use specialized var if it's the super-parent - $s_excludes = $definition->info_parent_def->excludes; - } else { - $s_excludes = $definition->info[$tokens[$i]->name]->excludes; - } - if ($s_excludes) { - array_pop($exclude_stack); - } - } - $i++; - } - - } - - //####################################################################// - // Post-processing - - // remove implicit parent tokens at the beginning and end - array_shift($tokens); - array_pop($tokens); - - // remove context variables - $context->destroy('IsInline'); - $context->destroy('CurrentToken'); - - //####################################################################// - // Return - - return $tokens; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php deleted file mode 100644 index c81b6b7b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php +++ /dev/null @@ -1,457 +0,0 @@ -getHTMLDefinition(); - - // local variables - $generator = new HTMLPurifier_Generator($config, $context); - $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); - $e = $context->get('ErrorCollector', true); - $t = false; // token index - $i = false; // injector index - $token = false; // the current token - $reprocess = false; // whether or not to reprocess the same token - $stack = array(); - - // member variables - $this->stack =& $stack; - $this->t =& $t; - $this->tokens =& $tokens; - $this->config = $config; - $this->context = $context; - - // context variables - $context->register('CurrentNesting', $stack); - $context->register('InputIndex', $t); - $context->register('InputTokens', $tokens); - $context->register('CurrentToken', $token); - - // -- begin INJECTOR -- - - $this->injectors = array(); - - $injectors = $config->getBatch('AutoFormat'); - $def_injectors = $definition->info_injector; - $custom_injectors = $injectors['Custom']; - unset($injectors['Custom']); // special case - foreach ($injectors as $injector => $b) { - // XXX: Fix with a legitimate lookup table of enabled filters - if (strpos($injector, '.') !== false) continue; - $injector = "HTMLPurifier_Injector_$injector"; - if (!$b) continue; - $this->injectors[] = new $injector; - } - foreach ($def_injectors as $injector) { - // assumed to be objects - $this->injectors[] = $injector; - } - foreach ($custom_injectors as $injector) { - if (is_string($injector)) { - $injector = "HTMLPurifier_Injector_$injector"; - $injector = new $injector; - } - $this->injectors[] = $injector; - } - - // give the injectors references to the definition and context - // variables for performance reasons - foreach ($this->injectors as $ix => $injector) { - $error = $injector->prepare($config, $context); - if (!$error) continue; - array_splice($this->injectors, $ix, 1); // rm the injector - trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); - } - - // -- end INJECTOR -- - - // a note on punting: - // In order to reduce code duplication, whenever some code needs - // to make HTML changes in order to make things "correct", the - // new HTML gets sent through the purifier, regardless of its - // status. This means that if we add a start token, because it - // was totally necessary, we don't have to update nesting; we just - // punt ($reprocess = true; continue;) and it does that for us. - - // isset is in loop because $tokens size changes during loop exec - for ( - $t = 0; - $t == 0 || isset($tokens[$t - 1]); - // only increment if we don't need to reprocess - $reprocess ? $reprocess = false : $t++ - ) { - - // check for a rewind - if (is_int($i) && $i >= 0) { - // possibility: disable rewinding if the current token has a - // rewind set on it already. This would offer protection from - // infinite loop, but might hinder some advanced rewinding. - $rewind_to = $this->injectors[$i]->getRewind(); - if (is_int($rewind_to) && $rewind_to < $t) { - if ($rewind_to < 0) $rewind_to = 0; - while ($t > $rewind_to) { - $t--; - $prev = $tokens[$t]; - // indicate that other injectors should not process this token, - // but we need to reprocess it - unset($prev->skip[$i]); - $prev->rewind = $i; - if ($prev instanceof HTMLPurifier_Token_Start) array_pop($this->stack); - elseif ($prev instanceof HTMLPurifier_Token_End) $this->stack[] = $prev->start; - } - } - $i = false; - } - - // handle case of document end - if (!isset($tokens[$t])) { - // kill processing if stack is empty - if (empty($this->stack)) break; - - // peek - $top_nesting = array_pop($this->stack); - $this->stack[] = $top_nesting; - - // send error - if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); - } - - // append, don't splice, since this is the end - $tokens[] = new HTMLPurifier_Token_End($top_nesting->name); - - // punt! - $reprocess = true; - continue; - } - - $token = $tokens[$t]; - - //echo '
      '; printTokens($tokens, $t); printTokens($this->stack); - - // quick-check: if it's not a tag, no need to process - if (empty($token->is_tag)) { - if ($token instanceof HTMLPurifier_Token_Text) { - foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleText($token); - $this->processToken($token, $i); - $reprocess = true; - break; - } - } - // another possibility is a comment - continue; - } - - if (isset($definition->info[$token->name])) { - $type = $definition->info[$token->name]->child->type; - } else { - $type = false; // Type is unknown, treat accordingly - } - - // quick tag checks: anything that's *not* an end tag - $ok = false; - if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { - // claims to be a start tag but is empty - $token = new HTMLPurifier_Token_Empty($token->name, $token->attr); - $ok = true; - } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { - // claims to be empty but really is a start tag - $this->swap(new HTMLPurifier_Token_End($token->name)); - $this->insertBefore(new HTMLPurifier_Token_Start($token->name, $token->attr)); - // punt (since we had to modify the input stream in a non-trivial way) - $reprocess = true; - continue; - } elseif ($token instanceof HTMLPurifier_Token_Empty) { - // real empty token - $ok = true; - } elseif ($token instanceof HTMLPurifier_Token_Start) { - // start tag - - // ...unless they also have to close their parent - if (!empty($this->stack)) { - - $parent = array_pop($this->stack); - $this->stack[] = $parent; - - if (isset($definition->info[$parent->name])) { - $elements = $definition->info[$parent->name]->child->getAllowedElements($config); - $autoclose = !isset($elements[$token->name]); - } else { - $autoclose = false; - } - - $carryover = false; - if ($autoclose && $definition->info[$parent->name]->formatting) { - $carryover = true; - } - - if ($autoclose) { - // errors need to be updated - $new_token = new HTMLPurifier_Token_End($parent->name); - $new_token->start = $parent; - if ($carryover) { - $element = clone $parent; - $element->armor['MakeWellFormed_TagClosedError'] = true; - $element->carryover = true; - $this->processToken(array($new_token, $token, $element)); - } else { - $this->insertBefore($new_token); - } - if ($e && !isset($parent->armor['MakeWellFormed_TagClosedError'])) { - if (!$carryover) { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', $parent); - } else { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $parent); - } - } - $reprocess = true; - continue; - } - - } - $ok = true; - } - - if ($ok) { - foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleElement($token); - $this->processToken($token, $i); - $reprocess = true; - break; - } - if (!$reprocess) { - // ah, nothing interesting happened; do normal processing - $this->swap($token); - if ($token instanceof HTMLPurifier_Token_Start) { - $this->stack[] = $token; - } elseif ($token instanceof HTMLPurifier_Token_End) { - throw new HTMLPurifier_Exception('Improper handling of end tag in start code; possible error in MakeWellFormed'); - } - } - continue; - } - - // sanity check: we should be dealing with a closing tag - if (!$token instanceof HTMLPurifier_Token_End) { - throw new HTMLPurifier_Exception('Unaccounted for tag token in input stream, bug in HTML Purifier'); - } - - // make sure that we have something open - if (empty($this->stack)) { - if ($escape_invalid_tags) { - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text'); - $this->swap(new HTMLPurifier_Token_Text( - $generator->generateFromToken($token) - )); - } else { - $this->remove(); - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed'); - } - $reprocess = true; - continue; - } - - // first, check for the simplest case: everything closes neatly. - // Eventually, everything passes through here; if there are problems - // we modify the input stream accordingly and then punt, so that - // the tokens get processed again. - $current_parent = array_pop($this->stack); - if ($current_parent->name == $token->name) { - $token->start = $current_parent; - foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleEnd($token); - $this->processToken($token, $i); - $this->stack[] = $current_parent; - $reprocess = true; - break; - } - continue; - } - - // okay, so we're trying to close the wrong tag - - // undo the pop previous pop - $this->stack[] = $current_parent; - - // scroll back the entire nest, trying to find our tag. - // (feature could be to specify how far you'd like to go) - $size = count($this->stack); - // -2 because -1 is the last element, but we already checked that - $skipped_tags = false; - for ($j = $size - 2; $j >= 0; $j--) { - if ($this->stack[$j]->name == $token->name) { - $skipped_tags = array_slice($this->stack, $j); - break; - } - } - - // we didn't find the tag, so remove - if ($skipped_tags === false) { - if ($escape_invalid_tags) { - $this->swap(new HTMLPurifier_Token_Text( - $generator->generateFromToken($token) - )); - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text'); - } else { - $this->remove(); - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed'); - } - $reprocess = true; - continue; - } - - // do errors, in REVERSE $j order: a,b,c with - $c = count($skipped_tags); - if ($e) { - for ($j = $c - 1; $j > 0; $j--) { - // notice we exclude $j == 0, i.e. the current ending tag, from - // the errors... - if (!isset($skipped_tags[$j]->armor['MakeWellFormed_TagClosedError'])) { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$j]); - } - } - } - - // insert tags, in FORWARD $j order: c,b,a with - $replace = array($token); - for ($j = 1; $j < $c; $j++) { - // ...as well as from the insertions - $new_token = new HTMLPurifier_Token_End($skipped_tags[$j]->name); - $new_token->start = $skipped_tags[$j]; - array_unshift($replace, $new_token); - if (isset($definition->info[$new_token->name]) && $definition->info[$new_token->name]->formatting) { - $element = clone $skipped_tags[$j]; - $element->carryover = true; - $element->armor['MakeWellFormed_TagClosedError'] = true; - $replace[] = $element; - } - } - $this->processToken($replace); - $reprocess = true; - continue; - } - - $context->destroy('CurrentNesting'); - $context->destroy('InputTokens'); - $context->destroy('InputIndex'); - $context->destroy('CurrentToken'); - - unset($this->injectors, $this->stack, $this->tokens, $this->t); - return $tokens; - } - - /** - * Processes arbitrary token values for complicated substitution patterns. - * In general: - * - * If $token is an array, it is a list of tokens to substitute for the - * current token. These tokens then get individually processed. If there - * is a leading integer in the list, that integer determines how many - * tokens from the stream should be removed. - * - * If $token is a regular token, it is swapped with the current token. - * - * If $token is false, the current token is deleted. - * - * If $token is an integer, that number of tokens (with the first token - * being the current one) will be deleted. - * - * @param $token Token substitution value - * @param $injector Injector that performed the substitution; default is if - * this is not an injector related operation. - */ - protected function processToken($token, $injector = -1) { - - // normalize forms of token - if (is_object($token)) $token = array(1, $token); - if (is_int($token)) $token = array($token); - if ($token === false) $token = array(1); - if (!is_array($token)) throw new HTMLPurifier_Exception('Invalid token type from injector'); - if (!is_int($token[0])) array_unshift($token, 1); - if ($token[0] === 0) throw new HTMLPurifier_Exception('Deleting zero tokens is not valid'); - - // $token is now an array with the following form: - // array(number nodes to delete, new node 1, new node 2, ...) - - $delete = array_shift($token); - $old = array_splice($this->tokens, $this->t, $delete, $token); - - if ($injector > -1) { - // determine appropriate skips - $oldskip = isset($old[0]) ? $old[0]->skip : array(); - foreach ($token as $object) { - $object->skip = $oldskip; - $object->skip[$injector] = true; - } - } - - } - - /** - * Inserts a token before the current token. Cursor now points to this token - */ - private function insertBefore($token) { - array_splice($this->tokens, $this->t, 0, array($token)); - } - - /** - * Removes current token. Cursor now points to new token occupying previously - * occupied space. - */ - private function remove() { - array_splice($this->tokens, $this->t, 1); - } - - /** - * Swap current token with new token. Cursor points to new token (no change). - */ - private function swap($token) { - $this->tokens[$this->t] = $token; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php deleted file mode 100644 index 9792a0f5..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php +++ /dev/null @@ -1,171 +0,0 @@ -getHTMLDefinition(); - $generator = new HTMLPurifier_Generator($config, $context); - $result = array(); - - $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); - $remove_invalid_img = $config->get('Core.RemoveInvalidImg'); - - // currently only used to determine if comments should be kept - $trusted = $config->get('HTML.Trusted'); - - $remove_script_contents = $config->get('Core.RemoveScriptContents'); - $hidden_elements = $config->get('Core.HiddenElements'); - - // remove script contents compatibility - if ($remove_script_contents === true) { - $hidden_elements['script'] = true; - } elseif ($remove_script_contents === false && isset($hidden_elements['script'])) { - unset($hidden_elements['script']); - } - - $attr_validator = new HTMLPurifier_AttrValidator(); - - // removes tokens until it reaches a closing tag with its value - $remove_until = false; - - // converts comments into text tokens when this is equal to a tag name - $textify_comments = false; - - $token = false; - $context->register('CurrentToken', $token); - - $e = false; - if ($config->get('Core.CollectErrors')) { - $e =& $context->get('ErrorCollector'); - } - - foreach($tokens as $token) { - if ($remove_until) { - if (empty($token->is_tag) || $token->name !== $remove_until) { - continue; - } - } - if (!empty( $token->is_tag )) { - // DEFINITION CALL - - // before any processing, try to transform the element - if ( - isset($definition->info_tag_transform[$token->name]) - ) { - $original_name = $token->name; - // there is a transformation for this tag - // DEFINITION CALL - $token = $definition-> - info_tag_transform[$token->name]-> - transform($token, $config, $context); - if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', $original_name); - } - - if (isset($definition->info[$token->name])) { - - // mostly everything's good, but - // we need to make sure required attributes are in order - if ( - ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) && - $definition->info[$token->name]->required_attr && - ($token->name != 'img' || $remove_invalid_img) // ensure config option still works - ) { - $attr_validator->validateToken($token, $config, $context); - $ok = true; - foreach ($definition->info[$token->name]->required_attr as $name) { - if (!isset($token->attr[$name])) { - $ok = false; - break; - } - } - if (!$ok) { - if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Missing required attribute', $name); - continue; - } - $token->armor['ValidateAttributes'] = true; - } - - if (isset($hidden_elements[$token->name]) && $token instanceof HTMLPurifier_Token_Start) { - $textify_comments = $token->name; - } elseif ($token->name === $textify_comments && $token instanceof HTMLPurifier_Token_End) { - $textify_comments = false; - } - - } elseif ($escape_invalid_tags) { - // invalid tag, generate HTML representation and insert in - if ($e) $e->send(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text'); - $token = new HTMLPurifier_Token_Text( - $generator->generateFromToken($token) - ); - } else { - // check if we need to destroy all of the tag's children - // CAN BE GENERICIZED - if (isset($hidden_elements[$token->name])) { - if ($token instanceof HTMLPurifier_Token_Start) { - $remove_until = $token->name; - } elseif ($token instanceof HTMLPurifier_Token_Empty) { - // do nothing: we're still looking - } else { - $remove_until = false; - } - if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed'); - } else { - if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed'); - } - continue; - } - } elseif ($token instanceof HTMLPurifier_Token_Comment) { - // textify comments in script tags when they are allowed - if ($textify_comments !== false) { - $data = $token->data; - $token = new HTMLPurifier_Token_Text($data); - } elseif ($trusted) { - // keep, but perform comment cleaning - if ($e) { - // perform check whether or not there's a trailing hyphen - if (substr($token->data, -1) == '-') { - $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed'); - } - } - $token->data = rtrim($token->data, '-'); - $found_double_hyphen = false; - while (strpos($token->data, '--') !== false) { - if ($e && !$found_double_hyphen) { - $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed'); - } - $found_double_hyphen = true; // prevent double-erroring - $token->data = str_replace('--', '-', $token->data); - } - } else { - // strip comments - if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); - continue; - } - } elseif ($token instanceof HTMLPurifier_Token_Text) { - } else { - continue; - } - $result[] = $token; - } - if ($remove_until && $e) { - // we removed tokens until the end, throw error - $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', $remove_until); - } - - $context->destroy('CurrentToken'); - - return $result; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php deleted file mode 100644 index d5e03b7b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php +++ /dev/null @@ -1,39 +0,0 @@ -register('CurrentToken', $token); - - foreach ($tokens as $key => $token) { - - // only process tokens that have attributes, - // namely start and empty tags - if (!$token instanceof HTMLPurifier_Token_Start && !$token instanceof HTMLPurifier_Token_Empty) continue; - - // skip tokens that are armored - if (!empty($token->armor['ValidateAttributes'])) continue; - - // note that we have no facilities here for removing tokens - $validator->validateToken($token, $config, $context); - - $tokens[$key] = $token; // for PHP 4 - } - $context->destroy('CurrentToken'); - - return $tokens; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHash.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHash.php deleted file mode 100644 index 2161685e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHash.php +++ /dev/null @@ -1,39 +0,0 @@ -accessed[$index] = true; - return parent::offsetGet($index); - } - - /** - * Returns a lookup array of all array indexes that have been accessed. - * @return Array in form array($index => true). - */ - public function getAccessed() { - return $this->accessed; - } - - /** - * Resets the access array. - */ - public function resetAccessed() { - $this->accessed = array(); - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHashParser.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHashParser.php deleted file mode 100644 index 03deefce..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHashParser.php +++ /dev/null @@ -1,110 +0,0 @@ - 'DefaultKeyValue', - * 'KEY' => 'Value', - * 'KEY2' => 'Value2', - * 'MULTILINE-KEY' => "Multiline\nvalue.\n", - * ) - * - * We use this as an easy to use file-format for configuration schema - * files, but the class itself is usage agnostic. - * - * You can use ---- to forcibly terminate parsing of a single string-hash; - * this marker is used in multi string-hashes to delimit boundaries. - */ -class HTMLPurifier_StringHashParser -{ - - public $default = 'ID'; - - /** - * Parses a file that contains a single string-hash. - */ - public function parseFile($file) { - if (!file_exists($file)) return false; - $fh = fopen($file, 'r'); - if (!$fh) return false; - $ret = $this->parseHandle($fh); - fclose($fh); - return $ret; - } - - /** - * Parses a file that contains multiple string-hashes delimited by '----' - */ - public function parseMultiFile($file) { - if (!file_exists($file)) return false; - $ret = array(); - $fh = fopen($file, 'r'); - if (!$fh) return false; - while (!feof($fh)) { - $ret[] = $this->parseHandle($fh); - } - fclose($fh); - return $ret; - } - - /** - * Internal parser that acepts a file handle. - * @note While it's possible to simulate in-memory parsing by using - * custom stream wrappers, if such a use-case arises we should - * factor out the file handle into its own class. - * @param $fh File handle with pointer at start of valid string-hash - * block. - */ - protected function parseHandle($fh) { - $state = false; - $single = false; - $ret = array(); - do { - $line = fgets($fh); - if ($line === false) break; - $line = rtrim($line, "\n\r"); - if (!$state && $line === '') continue; - if ($line === '----') break; - if (strncmp('--#', $line, 3) === 0) { - // Comment - continue; - } elseif (strncmp('--', $line, 2) === 0) { - // Multiline declaration - $state = trim($line, '- '); - if (!isset($ret[$state])) $ret[$state] = ''; - continue; - } elseif (!$state) { - $single = true; - if (strpos($line, ':') !== false) { - // Single-line declaration - list($state, $line) = explode(':', $line, 2); - $line = trim($line); - } else { - // Use default declaration - $state = $this->default; - } - } - if ($single) { - $ret[$state] = $line; - $single = false; - $state = false; - } else { - $ret[$state] .= "$line\n"; - } - } while (!feof($fh)); - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform.php deleted file mode 100644 index a8a1f45d..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform.php +++ /dev/null @@ -1,36 +0,0 @@ - 'xx-small', - '1' => 'xx-small', - '2' => 'small', - '3' => 'medium', - '4' => 'large', - '5' => 'x-large', - '6' => 'xx-large', - '7' => '300%', - '-1' => 'smaller', - '-2' => '60%', - '+1' => 'larger', - '+2' => '150%', - '+3' => '200%', - '+4' => '300%' - ); - - public function transform($tag, $config, $context) { - - if ($tag instanceof HTMLPurifier_Token_End) { - $new_tag = clone $tag; - $new_tag->name = $this->transform_to; - return $new_tag; - } - - $attr = $tag->attr; - $prepend_style = ''; - - // handle color transform - if (isset($attr['color'])) { - $prepend_style .= 'color:' . $attr['color'] . ';'; - unset($attr['color']); - } - - // handle face transform - if (isset($attr['face'])) { - $prepend_style .= 'font-family:' . $attr['face'] . ';'; - unset($attr['face']); - } - - // handle size transform - if (isset($attr['size'])) { - // normalize large numbers - if ($attr['size']{0} == '+' || $attr['size']{0} == '-') { - $size = (int) $attr['size']; - if ($size < -2) $attr['size'] = '-2'; - if ($size > 4) $attr['size'] = '+4'; - } else { - $size = (int) $attr['size']; - if ($size > 7) $attr['size'] = '7'; - } - if (isset($this->_size_lookup[$attr['size']])) { - $prepend_style .= 'font-size:' . - $this->_size_lookup[$attr['size']] . ';'; - } - unset($attr['size']); - } - - if ($prepend_style) { - $attr['style'] = isset($attr['style']) ? - $prepend_style . $attr['style'] : - $prepend_style; - } - - $new_tag = clone $tag; - $new_tag->name = $this->transform_to; - $new_tag->attr = $attr; - - return $new_tag; - - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php deleted file mode 100644 index ced91503..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php +++ /dev/null @@ -1,35 +0,0 @@ -transform_to = $transform_to; - $this->style = $style; - } - - public function transform($tag, $config, $context) { - $new_tag = clone $tag; - $new_tag->name = $this->transform_to; - if (!is_null($this->style) && - ($new_tag instanceof HTMLPurifier_Token_Start || $new_tag instanceof HTMLPurifier_Token_Empty) - ) { - $this->prependCSS($new_tag->attr, $this->style); - } - return $new_tag; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token.php deleted file mode 100644 index 22bebcf7..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token.php +++ /dev/null @@ -1,57 +0,0 @@ -line = $l; - $this->col = $c; - } - - /** - * Convenience function for DirectLex settings line/col position. - */ - public function rawPosition($l, $c) { - if ($c === -1) $l++; - $this->line = $l; - $this->col = $c; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Comment.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Comment.php deleted file mode 100644 index 592f2eea..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Comment.php +++ /dev/null @@ -1,22 +0,0 @@ -data = $data; - $this->line = $line; - $this->col = $col; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Empty.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Empty.php deleted file mode 100644 index 842c54da..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Empty.php +++ /dev/null @@ -1,11 +0,0 @@ -!empty($obj->is_tag) - * without having to use a function call is_a(). - */ - public $is_tag = true; - - /** - * The lower-case name of the tag, like 'a', 'b' or 'blockquote'. - * - * @note Strictly speaking, XML tags are case sensitive, so we shouldn't - * be lower-casing them, but these tokens cater to HTML tags, which are - * insensitive. - */ - public $name; - - /** - * Associative array of the tag's attributes. - */ - public $attr = array(); - - /** - * Non-overloaded constructor, which lower-cases passed tag name. - * - * @param $name String name. - * @param $attr Associative array of attributes. - */ - public function __construct($name, $attr = array(), $line = null, $col = null) { - $this->name = ctype_lower($name) ? $name : strtolower($name); - foreach ($attr as $key => $value) { - // normalization only necessary when key is not lowercase - if (!ctype_lower($key)) { - $new_key = strtolower($key); - if (!isset($attr[$new_key])) { - $attr[$new_key] = $attr[$key]; - } - if ($new_key !== $key) { - unset($attr[$key]); - } - } - } - $this->attr = $attr; - $this->line = $line; - $this->col = $col; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Text.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Text.php deleted file mode 100644 index 0d82f75a..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Text.php +++ /dev/null @@ -1,33 +0,0 @@ -data = $data; - $this->is_whitespace = ctype_space($data); - $this->line = $line; - $this->col = $col; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TokenFactory.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TokenFactory.php deleted file mode 100644 index 16c969cf..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TokenFactory.php +++ /dev/null @@ -1,94 +0,0 @@ -p_start = new HTMLPurifier_Token_Start('', array()); - $this->p_end = new HTMLPurifier_Token_End(''); - $this->p_empty = new HTMLPurifier_Token_Empty('', array()); - $this->p_text = new HTMLPurifier_Token_Text(''); - $this->p_comment= new HTMLPurifier_Token_Comment(''); - } - - /** - * Creates a HTMLPurifier_Token_Start. - * @param $name Tag name - * @param $attr Associative array of attributes - * @return Generated HTMLPurifier_Token_Start - */ - public function createStart($name, $attr = array()) { - $p = clone $this->p_start; - $p->__construct($name, $attr); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_End. - * @param $name Tag name - * @return Generated HTMLPurifier_Token_End - */ - public function createEnd($name) { - $p = clone $this->p_end; - $p->__construct($name); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Empty. - * @param $name Tag name - * @param $attr Associative array of attributes - * @return Generated HTMLPurifier_Token_Empty - */ - public function createEmpty($name, $attr = array()) { - $p = clone $this->p_empty; - $p->__construct($name, $attr); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Text. - * @param $data Data of text token - * @return Generated HTMLPurifier_Token_Text - */ - public function createText($data) { - $p = clone $this->p_text; - $p->__construct($data); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Comment. - * @param $data Data of comment token - * @return Generated HTMLPurifier_Token_Comment - */ - public function createComment($data) { - $p = clone $this->p_comment; - $p->__construct($data); - return $p; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URI.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URI.php deleted file mode 100644 index ac983b86..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URI.php +++ /dev/null @@ -1,173 +0,0 @@ -scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme); - $this->userinfo = $userinfo; - $this->host = $host; - $this->port = is_null($port) ? $port : (int) $port; - $this->path = $path; - $this->query = $query; - $this->fragment = $fragment; - } - - /** - * Retrieves a scheme object corresponding to the URI's scheme/default - * @param $config Instance of HTMLPurifier_Config - * @param $context Instance of HTMLPurifier_Context - * @return Scheme object appropriate for validating this URI - */ - public function getSchemeObj($config, $context) { - $registry = HTMLPurifier_URISchemeRegistry::instance(); - if ($this->scheme !== null) { - $scheme_obj = $registry->getScheme($this->scheme, $config, $context); - if (!$scheme_obj) return false; // invalid scheme, clean it out - } else { - // no scheme: retrieve the default one - $def = $config->getDefinition('URI'); - $scheme_obj = $registry->getScheme($def->defaultScheme, $config, $context); - if (!$scheme_obj) { - // something funky happened to the default scheme object - trigger_error( - 'Default scheme object "' . $def->defaultScheme . '" was not readable', - E_USER_WARNING - ); - return false; - } - } - return $scheme_obj; - } - - /** - * Generic validation method applicable for all schemes. May modify - * this URI in order to get it into a compliant form. - * @param $config Instance of HTMLPurifier_Config - * @param $context Instance of HTMLPurifier_Context - * @return True if validation/filtering succeeds, false if failure - */ - public function validate($config, $context) { - - // ABNF definitions from RFC 3986 - $chars_sub_delims = '!$&\'()*+,;='; - $chars_gen_delims = ':/?#[]@'; - $chars_pchar = $chars_sub_delims . ':@'; - - // validate scheme (MUST BE FIRST!) - if (!is_null($this->scheme) && is_null($this->host)) { - $def = $config->getDefinition('URI'); - if ($def->defaultScheme === $this->scheme) { - $this->scheme = null; - } - } - - // validate host - if (!is_null($this->host)) { - $host_def = new HTMLPurifier_AttrDef_URI_Host(); - $this->host = $host_def->validate($this->host, $config, $context); - if ($this->host === false) $this->host = null; - } - - // validate username - if (!is_null($this->userinfo)) { - $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':'); - $this->userinfo = $encoder->encode($this->userinfo); - } - - // validate port - if (!is_null($this->port)) { - if ($this->port < 1 || $this->port > 65535) $this->port = null; - } - - // validate path - $path_parts = array(); - $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/'); - if (!is_null($this->host)) { - // path-abempty (hier and relative) - $this->path = $segments_encoder->encode($this->path); - } elseif ($this->path !== '' && $this->path[0] === '/') { - // path-absolute (hier and relative) - if (strlen($this->path) >= 2 && $this->path[1] === '/') { - // This shouldn't ever happen! - $this->path = ''; - } else { - $this->path = $segments_encoder->encode($this->path); - } - } elseif (!is_null($this->scheme) && $this->path !== '') { - // path-rootless (hier) - // Short circuit evaluation means we don't need to check nz - $this->path = $segments_encoder->encode($this->path); - } elseif (is_null($this->scheme) && $this->path !== '') { - // path-noscheme (relative) - // (once again, not checking nz) - $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@'); - $c = strpos($this->path, '/'); - if ($c !== false) { - $this->path = - $segment_nc_encoder->encode(substr($this->path, 0, $c)) . - $segments_encoder->encode(substr($this->path, $c)); - } else { - $this->path = $segment_nc_encoder->encode($this->path); - } - } else { - // path-empty (hier and relative) - $this->path = ''; // just to be safe - } - - // qf = query and fragment - $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?'); - - if (!is_null($this->query)) { - $this->query = $qf_encoder->encode($this->query); - } - - if (!is_null($this->fragment)) { - $this->fragment = $qf_encoder->encode($this->fragment); - } - - return true; - - } - - /** - * Convert URI back to string - * @return String URI appropriate for output - */ - public function toString() { - // reconstruct authority - $authority = null; - if (!is_null($this->host)) { - $authority = ''; - if(!is_null($this->userinfo)) $authority .= $this->userinfo . '@'; - $authority .= $this->host; - if(!is_null($this->port)) $authority .= ':' . $this->port; - } - - // reconstruct the result - $result = ''; - if (!is_null($this->scheme)) $result .= $this->scheme . ':'; - if (!is_null($authority)) $result .= '//' . $authority; - $result .= $this->path; - if (!is_null($this->query)) $result .= '?' . $this->query; - if (!is_null($this->fragment)) $result .= '#' . $this->fragment; - - return $result; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIDefinition.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIDefinition.php deleted file mode 100644 index 86ac169c..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIDefinition.php +++ /dev/null @@ -1,93 +0,0 @@ -registerFilter(new HTMLPurifier_URIFilter_DisableExternal()); - $this->registerFilter(new HTMLPurifier_URIFilter_DisableExternalResources()); - $this->registerFilter(new HTMLPurifier_URIFilter_HostBlacklist()); - $this->registerFilter(new HTMLPurifier_URIFilter_MakeAbsolute()); - $this->registerFilter(new HTMLPurifier_URIFilter_Munge()); - } - - public function registerFilter($filter) { - $this->registeredFilters[$filter->name] = $filter; - } - - public function addFilter($filter, $config) { - $r = $filter->prepare($config); - if ($r === false) return; // null is ok, for backwards compat - if ($filter->post) { - $this->postFilters[$filter->name] = $filter; - } else { - $this->filters[$filter->name] = $filter; - } - } - - protected function doSetup($config) { - $this->setupMemberVariables($config); - $this->setupFilters($config); - } - - protected function setupFilters($config) { - foreach ($this->registeredFilters as $name => $filter) { - $conf = $config->get('URI.' . $name); - if ($conf !== false && $conf !== null) { - $this->addFilter($filter, $config); - } - } - unset($this->registeredFilters); - } - - protected function setupMemberVariables($config) { - $this->host = $config->get('URI.Host'); - $base_uri = $config->get('URI.Base'); - if (!is_null($base_uri)) { - $parser = new HTMLPurifier_URIParser(); - $this->base = $parser->parse($base_uri); - $this->defaultScheme = $this->base->scheme; - if (is_null($this->host)) $this->host = $this->base->host; - } - if (is_null($this->defaultScheme)) $this->defaultScheme = $config->get('URI.DefaultScheme'); - } - - public function filter(&$uri, $config, $context) { - foreach ($this->filters as $name => $f) { - $result = $f->filter($uri, $config, $context); - if (!$result) return false; - } - return true; - } - - public function postFilter(&$uri, $config, $context) { - foreach ($this->postFilters as $name => $f) { - $result = $f->filter($uri, $config, $context); - if (!$result) return false; - } - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter.php deleted file mode 100644 index 8c73051e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter.php +++ /dev/null @@ -1,45 +0,0 @@ -getDefinition('URI')->host; - if ($our_host !== null) $this->ourHostParts = array_reverse(explode('.', $our_host)); - } - public function filter(&$uri, $config, $context) { - if (is_null($uri->host)) return true; - if ($this->ourHostParts === false) return false; - $host_parts = array_reverse(explode('.', $uri->host)); - foreach ($this->ourHostParts as $i => $x) { - if (!isset($host_parts[$i])) return false; - if ($host_parts[$i] != $this->ourHostParts[$i]) return false; - } - return true; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php deleted file mode 100644 index b10370c9..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php +++ /dev/null @@ -1,12 +0,0 @@ -get('EmbeddedURI', true)) return true; - return parent::filter($uri, $config, $context); - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php deleted file mode 100644 index 11463f8f..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php +++ /dev/null @@ -1,21 +0,0 @@ -blacklist = $config->get('URI.HostBlacklist'); - return true; - } - public function filter(&$uri, $config, $context) { - foreach($this->blacklist as $blacklisted_host_fragment) { - if (strpos($uri->host, $blacklisted_host_fragment) !== false) { - return false; - } - } - return true; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php deleted file mode 100644 index 5f3c5ad3..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php +++ /dev/null @@ -1,114 +0,0 @@ -getDefinition('URI'); - $this->base = $def->base; - if (is_null($this->base)) { - trigger_error('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration', E_USER_WARNING); - return false; - } - $this->base->fragment = null; // fragment is invalid for base URI - $stack = explode('/', $this->base->path); - array_pop($stack); // discard last segment - $stack = $this->_collapseStack($stack); // do pre-parsing - $this->basePathStack = $stack; - return true; - } - public function filter(&$uri, $config, $context) { - if (is_null($this->base)) return true; // abort early - if ( - $uri->path === '' && is_null($uri->scheme) && - is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment) - ) { - // reference to current document - $uri = clone $this->base; - return true; - } - if (!is_null($uri->scheme)) { - // absolute URI already: don't change - if (!is_null($uri->host)) return true; - $scheme_obj = $uri->getSchemeObj($config, $context); - if (!$scheme_obj) { - // scheme not recognized - return false; - } - if (!$scheme_obj->hierarchical) { - // non-hierarchal URI with explicit scheme, don't change - return true; - } - // special case: had a scheme but always is hierarchical and had no authority - } - if (!is_null($uri->host)) { - // network path, don't bother - return true; - } - if ($uri->path === '') { - $uri->path = $this->base->path; - } elseif ($uri->path[0] !== '/') { - // relative path, needs more complicated processing - $stack = explode('/', $uri->path); - $new_stack = array_merge($this->basePathStack, $stack); - if ($new_stack[0] !== '' && !is_null($this->base->host)) { - array_unshift($new_stack, ''); - } - $new_stack = $this->_collapseStack($new_stack); - $uri->path = implode('/', $new_stack); - } else { - // absolute path, but still we should collapse - $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path))); - } - // re-combine - $uri->scheme = $this->base->scheme; - if (is_null($uri->userinfo)) $uri->userinfo = $this->base->userinfo; - if (is_null($uri->host)) $uri->host = $this->base->host; - if (is_null($uri->port)) $uri->port = $this->base->port; - return true; - } - - /** - * Resolve dots and double-dots in a path stack - */ - private function _collapseStack($stack) { - $result = array(); - $is_folder = false; - for ($i = 0; isset($stack[$i]); $i++) { - $is_folder = false; - // absorb an internally duplicated slash - if ($stack[$i] == '' && $i && isset($stack[$i+1])) continue; - if ($stack[$i] == '..') { - if (!empty($result)) { - $segment = array_pop($result); - if ($segment === '' && empty($result)) { - // error case: attempted to back out too far: - // restore the leading slash - $result[] = ''; - } elseif ($segment === '..') { - $result[] = '..'; // cannot remove .. with .. - } - } else { - // relative path, preserve the double-dots - $result[] = '..'; - } - $is_folder = true; - continue; - } - if ($stack[$i] == '.') { - // silently absorb - $is_folder = true; - continue; - } - $result[] = $stack[$i]; - } - if ($is_folder) $result[] = ''; - return $result; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php deleted file mode 100644 index 16969bed..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php +++ /dev/null @@ -1,58 +0,0 @@ -target = $config->get('URI.' . $this->name); - $this->parser = new HTMLPurifier_URIParser(); - $this->doEmbed = $config->get('URI.MungeResources'); - $this->secretKey = $config->get('URI.MungeSecretKey'); - return true; - } - public function filter(&$uri, $config, $context) { - if ($context->get('EmbeddedURI', true) && !$this->doEmbed) return true; - - $scheme_obj = $uri->getSchemeObj($config, $context); - if (!$scheme_obj) return true; // ignore unknown schemes, maybe another postfilter did it - if (is_null($uri->host) || empty($scheme_obj->browsable)) { - return true; - } - // don't redirect if target host is our host - if ($uri->host === $config->getDefinition('URI')->host) { - return true; - } - - $this->makeReplace($uri, $config, $context); - $this->replace = array_map('rawurlencode', $this->replace); - - $new_uri = strtr($this->target, $this->replace); - $new_uri = $this->parser->parse($new_uri); - // don't redirect if the target host is the same as the - // starting host - if ($uri->host === $new_uri->host) return true; - $uri = $new_uri; // overwrite - return true; - } - - protected function makeReplace($uri, $config, $context) { - $string = $uri->toString(); - // always available - $this->replace['%s'] = $string; - $this->replace['%r'] = $context->get('EmbeddedURI', true); - $token = $context->get('CurrentToken', true); - $this->replace['%n'] = $token ? $token->name : null; - $this->replace['%m'] = $context->get('CurrentAttr', true); - $this->replace['%p'] = $context->get('CurrentCSSProperty', true); - // not always available - if ($this->secretKey) $this->replace['%t'] = sha1($this->secretKey . ':' . $string); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIParser.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIParser.php deleted file mode 100644 index 902f5270..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIParser.php +++ /dev/null @@ -1,70 +0,0 @@ -percentEncoder = new HTMLPurifier_PercentEncoder(); - } - - /** - * Parses a URI. - * @param $uri string URI to parse - * @return HTMLPurifier_URI representation of URI. This representation has - * not been validated yet and may not conform to RFC. - */ - public function parse($uri) { - - $uri = $this->percentEncoder->normalize($uri); - - // Regexp is as per Appendix B. - // Note that ["<>] are an addition to the RFC's recommended - // characters, because they represent external delimeters. - $r_URI = '!'. - '(([^:/?#"<>]+):)?'. // 2. Scheme - '(//([^/?#"<>]*))?'. // 4. Authority - '([^?#"<>]*)'. // 5. Path - '(\?([^#"<>]*))?'. // 7. Query - '(#([^"<>]*))?'. // 8. Fragment - '!'; - - $matches = array(); - $result = preg_match($r_URI, $uri, $matches); - - if (!$result) return false; // *really* invalid URI - - // seperate out parts - $scheme = !empty($matches[1]) ? $matches[2] : null; - $authority = !empty($matches[3]) ? $matches[4] : null; - $path = $matches[5]; // always present, can be empty - $query = !empty($matches[6]) ? $matches[7] : null; - $fragment = !empty($matches[8]) ? $matches[9] : null; - - // further parse authority - if ($authority !== null) { - $r_authority = "/^((.+?)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/"; - $matches = array(); - preg_match($r_authority, $authority, $matches); - $userinfo = !empty($matches[1]) ? $matches[2] : null; - $host = !empty($matches[3]) ? $matches[3] : ''; - $port = !empty($matches[4]) ? (int) $matches[5] : null; - } else { - $port = $host = $userinfo = null; - } - - return new HTMLPurifier_URI( - $scheme, $userinfo, $host, $port, $path, $query, $fragment); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme.php deleted file mode 100644 index 2ef2ae55..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme.php +++ /dev/null @@ -1,42 +0,0 @@ -, resolves edge cases - * with making relative URIs absolute - */ - public $hierarchical = false; - - /** - * Validates the components of a URI - * @note This implementation should be called by children if they define - * a default port, as it does port processing. - * @param $uri Instance of HTMLPurifier_URI - * @param $config HTMLPurifier_Config object - * @param $context HTMLPurifier_Context object - * @return Bool success or failure - */ - public function validate(&$uri, $config, $context) { - if ($this->default_port == $uri->port) $uri->port = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php deleted file mode 100644 index f86f5f27..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php +++ /dev/null @@ -1,43 +0,0 @@ -query = null; - - // typecode check - $semicolon_pos = strrpos($uri->path, ';'); // reverse - if ($semicolon_pos !== false) { - $type = substr($uri->path, $semicolon_pos + 1); // no semicolon - $uri->path = substr($uri->path, 0, $semicolon_pos); - $type_ret = ''; - if (strpos($type, '=') !== false) { - // figure out whether or not the declaration is correct - list($key, $typecode) = explode('=', $type, 2); - if ($key !== 'type') { - // invalid key, tack it back on encoded - $uri->path .= '%3B' . $type; - } elseif ($typecode === 'a' || $typecode === 'i' || $typecode === 'd') { - $type_ret = ";type=$typecode"; - } - } else { - $uri->path .= '%3B' . $type; - } - $uri->path = str_replace(';', '%3B', $uri->path); - $uri->path .= $type_ret; - } - - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/http.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/http.php deleted file mode 100644 index 1a5ccbe9..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/http.php +++ /dev/null @@ -1,20 +0,0 @@ -userinfo = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/https.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/https.php deleted file mode 100644 index ec1597bd..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/https.php +++ /dev/null @@ -1,12 +0,0 @@ -userinfo = null; - $uri->host = null; - $uri->port = null; - // we need to validate path against RFC 2368's addr-spec - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/news.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/news.php deleted file mode 100644 index 11a8f229..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/news.php +++ /dev/null @@ -1,22 +0,0 @@ -userinfo = null; - $uri->host = null; - $uri->port = null; - $uri->query = null; - // typecode check needed on path - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php deleted file mode 100644 index 57a05451..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php +++ /dev/null @@ -1,20 +0,0 @@ -userinfo = null; - $uri->query = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php deleted file mode 100644 index ad227a43..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php +++ /dev/null @@ -1,68 +0,0 @@ -get('URI.AllowedSchemes'); - if (!$config->get('URI.OverrideAllowedSchemes') && - !isset($allowed_schemes[$scheme]) - ) { - return; - } - - if (isset($this->schemes[$scheme])) return $this->schemes[$scheme]; - if (!isset($allowed_schemes[$scheme])) return; - - $class = 'HTMLPurifier_URIScheme_' . $scheme; - if (!class_exists($class)) return; - $this->schemes[$scheme] = new $class(); - return $this->schemes[$scheme]; - } - - /** - * Registers a custom scheme to the cache, bypassing reflection. - * @param $scheme Scheme name - * @param $scheme_obj HTMLPurifier_URIScheme object - */ - public function register($scheme, $scheme_obj) { - $this->schemes[$scheme] = $scheme_obj; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/UnitConverter.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/UnitConverter.php deleted file mode 100644 index 1944fad9..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/UnitConverter.php +++ /dev/null @@ -1,254 +0,0 @@ - array( - 'px' => 3, // This is as per CSS 2.1 and Firefox. Your mileage may vary - 'pt' => 4, - 'pc' => 48, - 'in' => 288, - self::METRIC => array('pt', '0.352777778', 'mm'), - ), - self::METRIC => array( - 'mm' => 1, - 'cm' => 10, - self::ENGLISH => array('mm', '2.83464567', 'pt'), - ), - ); - - /** - * Minimum bcmath precision for output. - */ - protected $outputPrecision; - - /** - * Bcmath precision for internal calculations. - */ - protected $internalPrecision; - - /** - * Whether or not BCMath is available - */ - private $bcmath; - - public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false) { - $this->outputPrecision = $output_precision; - $this->internalPrecision = $internal_precision; - $this->bcmath = !$force_no_bcmath && function_exists('bcmul'); - } - - /** - * Converts a length object of one unit into another unit. - * @param HTMLPurifier_Length $length - * Instance of HTMLPurifier_Length to convert. You must validate() - * it before passing it here! - * @param string $to_unit - * Unit to convert to. - * @note - * About precision: This conversion function pays very special - * attention to the incoming precision of values and attempts - * to maintain a number of significant figure. Results are - * fairly accurate up to nine digits. Some caveats: - * - If a number is zero-padded as a result of this significant - * figure tracking, the zeroes will be eliminated. - * - If a number contains less than four sigfigs ($outputPrecision) - * and this causes some decimals to be excluded, those - * decimals will be added on. - */ - public function convert($length, $to_unit) { - - if (!$length->isValid()) return false; - - $n = $length->getN(); - $unit = $length->getUnit(); - - if ($n === '0' || $unit === false) { - return new HTMLPurifier_Length('0', false); - } - - $state = $dest_state = false; - foreach (self::$units as $k => $x) { - if (isset($x[$unit])) $state = $k; - if (isset($x[$to_unit])) $dest_state = $k; - } - if (!$state || !$dest_state) return false; - - // Some calculations about the initial precision of the number; - // this will be useful when we need to do final rounding. - $sigfigs = $this->getSigFigs($n); - if ($sigfigs < $this->outputPrecision) $sigfigs = $this->outputPrecision; - - // BCMath's internal precision deals only with decimals. Use - // our default if the initial number has no decimals, or increase - // it by how ever many decimals, thus, the number of guard digits - // will always be greater than or equal to internalPrecision. - $log = (int) floor(log(abs($n), 10)); - $cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision - - for ($i = 0; $i < 2; $i++) { - - // Determine what unit IN THIS SYSTEM we need to convert to - if ($dest_state === $state) { - // Simple conversion - $dest_unit = $to_unit; - } else { - // Convert to the smallest unit, pending a system shift - $dest_unit = self::$units[$state][$dest_state][0]; - } - - // Do the conversion if necessary - if ($dest_unit !== $unit) { - $factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp); - $n = $this->mul($n, $factor, $cp); - $unit = $dest_unit; - } - - // Output was zero, so bail out early. Shouldn't ever happen. - if ($n === '') { - $n = '0'; - $unit = $to_unit; - break; - } - - // It was a simple conversion, so bail out - if ($dest_state === $state) { - break; - } - - if ($i !== 0) { - // Conversion failed! Apparently, the system we forwarded - // to didn't have this unit. This should never happen! - return false; - } - - // Pre-condition: $i == 0 - - // Perform conversion to next system of units - $n = $this->mul($n, self::$units[$state][$dest_state][1], $cp); - $unit = self::$units[$state][$dest_state][2]; - $state = $dest_state; - - // One more loop around to convert the unit in the new system. - - } - - // Post-condition: $unit == $to_unit - if ($unit !== $to_unit) return false; - - // Useful for debugging: - //echo "
      n";
      -        //echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n
      \n"; - - $n = $this->round($n, $sigfigs); - if (strpos($n, '.') !== false) $n = rtrim($n, '0'); - $n = rtrim($n, '.'); - - return new HTMLPurifier_Length($n, $unit); - } - - /** - * Returns the number of significant figures in a string number. - * @param string $n Decimal number - * @return int number of sigfigs - */ - public function getSigFigs($n) { - $n = ltrim($n, '0+-'); - $dp = strpos($n, '.'); // decimal position - if ($dp === false) { - $sigfigs = strlen(rtrim($n, '0')); - } else { - $sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character - if ($dp !== 0) $sigfigs--; - } - return $sigfigs; - } - - /** - * Adds two numbers, using arbitrary precision when available. - */ - private function add($s1, $s2, $scale) { - if ($this->bcmath) return bcadd($s1, $s2, $scale); - else return $this->scale($s1 + $s2, $scale); - } - - /** - * Multiples two numbers, using arbitrary precision when available. - */ - private function mul($s1, $s2, $scale) { - if ($this->bcmath) return bcmul($s1, $s2, $scale); - else return $this->scale($s1 * $s2, $scale); - } - - /** - * Divides two numbers, using arbitrary precision when available. - */ - private function div($s1, $s2, $scale) { - if ($this->bcmath) return bcdiv($s1, $s2, $scale); - else return $this->scale($s1 / $s2, $scale); - } - - /** - * Rounds a number according to the number of sigfigs it should have, - * using arbitrary precision when available. - */ - private function round($n, $sigfigs) { - $new_log = (int) floor(log(abs($n), 10)); // Number of digits left of decimal - 1 - $rp = $sigfigs - $new_log - 1; // Number of decimal places needed - $neg = $n < 0 ? '-' : ''; // Negative sign - if ($this->bcmath) { - if ($rp >= 0) { - $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1); - $n = bcdiv($n, '1', $rp); - } else { - // This algorithm partially depends on the standardized - // form of numbers that comes out of bcmath. - $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0); - $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1); - } - return $n; - } else { - return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1); - } - } - - /** - * Scales a float to $scale digits right of decimal point, like BCMath. - */ - private function scale($r, $scale) { - if ($scale < 0) { - // The f sprintf type doesn't support negative numbers, so we - // need to cludge things manually. First get the string. - $r = sprintf('%.0f', (float) $r); - // Due to floating point precision loss, $r will more than likely - // look something like 4652999999999.9234. We grab one more digit - // than we need to precise from $r and then use that to round - // appropriately. - $precise = (string) round(substr($r, 0, strlen($r) + $scale), -1); - // Now we return it, truncating the zero that was rounded off. - return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); - } - return sprintf('%.' . $scale . 'f', (float) $r); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser.php deleted file mode 100644 index f5dbb536..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser.php +++ /dev/null @@ -1,154 +0,0 @@ - self::STRING, - 'istring' => self::ISTRING, - 'text' => self::TEXT, - 'itext' => self::ITEXT, - 'int' => self::INT, - 'float' => self::FLOAT, - 'bool' => self::BOOL, - 'lookup' => self::LOOKUP, - 'list' => self::ALIST, - 'hash' => self::HASH, - 'mixed' => self::MIXED - ); - - /** - * Lookup table of types that are string, and can have aliases or - * allowed value lists. - */ - static public $stringTypes = array( - self::STRING => true, - self::ISTRING => true, - self::TEXT => true, - self::ITEXT => true, - ); - - /** - * Validate a variable according to type. Throws - * HTMLPurifier_VarParserException if invalid. - * It may return NULL as a valid type if $allow_null is true. - * - * @param $var Variable to validate - * @param $type Type of variable, see HTMLPurifier_VarParser->types - * @param $allow_null Whether or not to permit null as a value - * @return Validated and type-coerced variable - */ - final public function parse($var, $type, $allow_null = false) { - if (is_string($type)) { - if (!isset(HTMLPurifier_VarParser::$types[$type])) { - throw new HTMLPurifier_VarParserException("Invalid type '$type'"); - } else { - $type = HTMLPurifier_VarParser::$types[$type]; - } - } - $var = $this->parseImplementation($var, $type, $allow_null); - if ($allow_null && $var === null) return null; - // These are basic checks, to make sure nothing horribly wrong - // happened in our implementations. - switch ($type) { - case (self::STRING): - case (self::ISTRING): - case (self::TEXT): - case (self::ITEXT): - if (!is_string($var)) break; - if ($type == self::ISTRING || $type == self::ITEXT) $var = strtolower($var); - return $var; - case (self::INT): - if (!is_int($var)) break; - return $var; - case (self::FLOAT): - if (!is_float($var)) break; - return $var; - case (self::BOOL): - if (!is_bool($var)) break; - return $var; - case (self::LOOKUP): - case (self::ALIST): - case (self::HASH): - if (!is_array($var)) break; - if ($type === self::LOOKUP) { - foreach ($var as $k) if ($k !== true) $this->error('Lookup table contains value other than true'); - } elseif ($type === self::ALIST) { - $keys = array_keys($var); - if (array_keys($keys) !== $keys) $this->error('Indices for list are not uniform'); - } - return $var; - case (self::MIXED): - return $var; - default: - $this->errorInconsistent(get_class($this), $type); - } - $this->errorGeneric($var, $type); - } - - /** - * Actually implements the parsing. Base implementation is to not - * do anything to $var. Subclasses should overload this! - */ - protected function parseImplementation($var, $type, $allow_null) { - return $var; - } - - /** - * Throws an exception. - */ - protected function error($msg) { - throw new HTMLPurifier_VarParserException($msg); - } - - /** - * Throws an inconsistency exception. - * @note This should not ever be called. It would be called if we - * extend the allowed values of HTMLPurifier_VarParser without - * updating subclasses. - */ - protected function errorInconsistent($class, $type) { - throw new HTMLPurifier_Exception("Inconsistency in $class: ".HTMLPurifier_VarParser::getTypeName($type)." not implemented"); - } - - /** - * Generic error for if a type didn't work. - */ - protected function errorGeneric($var, $type) { - $vtype = gettype($var); - $this->error("Expected type ".HTMLPurifier_VarParser::getTypeName($type).", got $vtype"); - } - - static public function getTypeName($type) { - static $lookup; - if (!$lookup) { - // Lazy load the alternative lookup table - $lookup = array_flip(HTMLPurifier_VarParser::$types); - } - if (!isset($lookup[$type])) return 'unknown'; - return $lookup[$type]; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php deleted file mode 100644 index e5998e5e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php +++ /dev/null @@ -1,96 +0,0 @@ - $j) $var[$i] = trim($j); - if ($type === self::HASH) { - // key:value,key2:value2 - $nvar = array(); - foreach ($var as $keypair) { - $c = explode(':', $keypair, 2); - if (!isset($c[1])) continue; - $nvar[$c[0]] = $c[1]; - } - $var = $nvar; - } - } - if (!is_array($var)) break; - $keys = array_keys($var); - if ($keys === array_keys($keys)) { - if ($type == self::ALIST) return $var; - elseif ($type == self::LOOKUP) { - $new = array(); - foreach ($var as $key) { - $new[$key] = true; - } - return $new; - } else break; - } - if ($type === self::LOOKUP) { - foreach ($var as $key => $value) { - $var[$key] = true; - } - } - return $var; - default: - $this->errorInconsistent(__CLASS__, $type); - } - $this->errorGeneric($var, $type); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Native.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Native.php deleted file mode 100644 index cdd342fa..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Native.php +++ /dev/null @@ -1,26 +0,0 @@ -evalExpression($var); - } - - protected function evalExpression($expr) { - $var = null; - $result = eval("\$var = $expr;"); - if ($result === false) { - throw new HTMLPurifier_VarParserException("Fatal error in evaluated code"); - } - return $var; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParserException.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParserException.php deleted file mode 100644 index fe30cc79..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParserException.php +++ /dev/null @@ -1,11 +0,0 @@ - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - vim: et sw=4 sts=4 diff --git a/modules/gallery/libraries/HtmlPurifier.php b/modules/gallery/libraries/HtmlPurifier.php deleted file mode 100644 index daa5896e..00000000 --- a/modules/gallery/libraries/HtmlPurifier.php +++ /dev/null @@ -1,38 +0,0 @@ - $key_value) { - foreach ($key_value as $key => $value) { - $purifier_config->set("$category.$key", $value); - } - } - self::$_instance = new HtmlPurifier($purifier_config); - } - - return self::$_instance; - } -} diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index cc542e01..32ef1905 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -83,7 +83,7 @@ class SafeString_Core { * Safe for use in HTML. * * Example:
      -   *   
      + *
      *
      * @return the string escaped for use in HTML. */ @@ -128,7 +128,7 @@ class SafeString_Core { * Safe for use HTML (purified HTML) * * Example:
      -   *   
      purified_html() ?> + *
      purified_html() ?> *
      * @return the string escaped for use in HTML. */ @@ -154,16 +154,22 @@ class SafeString_Core { // 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); + if (module::is_active("htmlpurifier")) { + if (empty(self::$_purifier)) { + require_once(MODPATH . "htmlpurifier/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); } - self::$_purifier = new HTMLPurifier($config); + Kohana::log("error", "Purify: " . $dirty_html); + return self::$_purifier->purify($dirty_html); + } else { + Kohana::log("error", "revert to clean: " . $dirty_html); + return self::_escape_for_html($dirty_html); } - return self::$_purifier->purify($dirty_html); } } -- cgit v1.2.3 From f2bbb2963a03c7f838772fa89facc0e38c3e4f4e Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 2 Sep 2009 07:07:47 -0700 Subject: Remove debugging statementes --- modules/gallery/libraries/SafeString.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 32ef1905..800647fa 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -165,10 +165,8 @@ class SafeString_Core { } self::$_purifier = new HTMLPurifier($config); } - Kohana::log("error", "Purify: " . $dirty_html); return self::$_purifier->purify($dirty_html); } else { - Kohana::log("error", "revert to clean: " . $dirty_html); return self::_escape_for_html($dirty_html); } } -- cgit v1.2.3 From a09a6a06bef1ff08e09a2855b308e20ea739ca1e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:28:41 -0700 Subject: Refactor how we use $this->relative_path() so that we're not calling it twice on both sides of a ternary operator. --- modules/gallery/models/item.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'modules') diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 68e89db6..8905a627 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -188,9 +188,8 @@ class Item_Model extends ORM_MPTT { * photo: http://example.com/gallery3/var/albums/album1/photo.jpg */ public function file_url($full_uri=false) { - return $full_uri ? - url::abs_file("var/albums/" . $this->relative_path()) : - url::file("var/albums/" . $this->relative_path()); + $relative_path = "var/albums/" . $this->relative_path(); + return $full_uri ? url::abs_file($relative_path) : url::file($relative_path); } /** @@ -222,9 +221,8 @@ class Item_Model extends ORM_MPTT { */ public function thumb_url($full_uri=false) { $cache_buster = "?m=" . $this->updated; - $base = ($full_uri ? - url::abs_file("var/thumbs/" . $this->relative_path()) : - url::file("var/thumbs/" . $this->relative_path())); + $relative_path = "var/thumbs/" . $this->relative_path(); + $base = ($full_uri ? url::abs_file($relative_path) : url::file($relative_path)); if ($this->is_photo()) { return $base . $cache_buster; } else if ($this->is_album()) { @@ -250,9 +248,8 @@ class Item_Model extends ORM_MPTT { * photo: http://example.com/gallery3/var/albums/album1/photo.resize.jpg */ public function resize_url($full_uri=false) { - return ($full_uri ? - url::abs_file("var/resizes/" . $this->relative_path()) : - url::file("var/resizes/" . $this->relative_path())) . + $relative_path = "var/resizes/" . $this->relative_path(); + return ($full_uri ? url::abs_file($relative_path) : url::file($relative_path)) . ($this->is_album() ? "/.album.jpg" : ""); } -- cgit v1.2.3 From 79754c2ef477c98740166a2a86fb491e0b07944e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:53:10 -0700 Subject: Run 'graphics::choose_default_toolkit();' to pick a toolkit, which we normally do as part of a regular install. --- modules/gallery_unit_test/controllers/gallery_unit_test.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'modules') diff --git a/modules/gallery_unit_test/controllers/gallery_unit_test.php b/modules/gallery_unit_test/controllers/gallery_unit_test.php index 8f3353dc..a5dbcc1f 100644 --- a/modules/gallery_unit_test/controllers/gallery_unit_test.php +++ b/modules/gallery_unit_test/controllers/gallery_unit_test.php @@ -122,6 +122,9 @@ class Gallery_Unit_Test_Controller extends Controller { module::activate($module_name); } + // Trigger late-binding install actions (defined in gallery_event::user_login) + graphics::choose_default_toolkit(); + $filter = count($_SERVER["argv"]) > 2 ? $_SERVER["argv"][2] : null; print new Unit_Test($modules, $filter); } catch (Exception $e) { -- cgit v1.2.3 From b9293755c03a6bf55a33732968481aa7a73fcce0 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:57:20 -0700 Subject: Deal with the aftermath of adding sharpen() calls. Since GD does not support it, this causes crashes as soon as you try to use it, which breaks a bunch of our tests. Also, give the user some idea that sharpen() is missing in the UI. Fixes #689. --- modules/gallery/helpers/graphics.php | 37 ++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 521dc5a4..66182a68 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -206,11 +206,13 @@ class graphics_Core { // Image would get upscaled; do nothing copy($input_file, $output_file); } else { - Image::factory($input_file) + $image = Image::factory($input_file) ->resize($options["width"], $options["height"], $options["master"]) - ->quality(module::get_var("gallery", "image_quality")) - ->sharpen(module::get_var("gallery", "image_sharpen")) - ->save($output_file); + ->quality(module::get_var("gallery", "image_quality")); + if (graphics::can("sharpen")) { + $image->sharpen(module::get_var("gallery", "image_sharpen")); + } + $image->save($output_file); } module::event("graphics_resize_completed", $input_file, $output_file, $options); @@ -352,13 +354,22 @@ class graphics_Core { $toolkits->gd->installed = true; $toolkits->gd->version = $gd["GD Version"]; $toolkits->gd->rotate = function_exists("imagerotate"); + $toolkits->gd->sharpen = function_exists("imageconvolution"); $toolkits->gd->binary = ""; $toolkits->gd->dir = ""; - if (!$toolkits->gd->rotate) { + if (!$toolkits->gd->rotate && !$toolkits->gd->sharpen) { + $toolkits->gd->error = + t("You have GD version %version, but it lacks image rotation and sharpening.", + array("version" => $gd["GD Version"])); + } else if (!$toolkits->gd->rotate) { $toolkits->gd->error = t("You have GD version %version, but it lacks image rotation.", array("version" => $gd["GD Version"])); + } else if (!$toolkits->gd->sharpen) { + $toolkits->gd->error = + t("You have GD version %version, but it lacks image sharpening.", + array("version" => $gd["GD Version"])); } } @@ -387,6 +398,7 @@ class graphics_Core { $toolkits->imagemagick->binary = $path; $toolkits->imagemagick->dir = dirname($path); $toolkits->imagemagick->rotate = true; + $toolkits->imagemagick->sharpen = true; } else { $toolkits->imagemagick->installed = false; $toolkits->imagemagick->error = @@ -411,6 +423,7 @@ class graphics_Core { $toolkits->graphicsmagick->binary = $path; $toolkits->graphicsmagick->dir = dirname($path); $toolkits->graphicsmagick->rotate = true; + $toolkits->graphicsmagick->sharpen = true; } else { $toolkits->graphicsmagick->installed = false; $toolkits->graphicsmagick->error = @@ -475,14 +488,18 @@ class graphics_Core { /** * Verify that a specific graphics function is available with the active toolkit. - * @param string $func (eg rotate, resize) + * @param string $func (eg rotate, sharpen) * @return boolean */ static function can($func) { - if (module::get_var("gallery", "graphics_toolkit") == "gd" && - $func == "rotate" && - !function_exists("imagerotate")) { - return false; + if (module::get_var("gallery", "graphics_toolkit") == "gd") { + switch ($func) { + case "rotate": + return function_exists("imagerotate"); + + case "sharpen": + return function_exists("imageconvolution"); + } } return true; -- cgit v1.2.3 From b842a9d9ca21d07241b5fa11c5263e18f830c88b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:58:04 -0700 Subject: Fix formatting, and use a properly named file in change_photo_no_csrf_fails_test() so that GD doesn't bomb. --- modules/gallery/tests/Photos_Controller_Test.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/Photos_Controller_Test.php b/modules/gallery/tests/Photos_Controller_Test.php index f7d3f72f..5c4802c2 100644 --- a/modules/gallery/tests/Photos_Controller_Test.php +++ b/modules/gallery/tests/Photos_Controller_Test.php @@ -33,8 +33,8 @@ class Photos_Controller_Test extends Unit_Test_Case { public function change_photo_test() { $controller = new Photos_Controller(); $root = ORM::factory("item", 1); - $this->_photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test.jpeg", "test", - "test"); + $this->_photo = photo::create( + $root, MODPATH . "gallery/tests/test.jpg", "test.jpeg", "test", "test"); $orig_name = $this->_photo->name; $_POST["filename"] = "test.jpeg"; @@ -63,7 +63,8 @@ class Photos_Controller_Test extends Unit_Test_Case { public function change_photo_no_csrf_fails_test() { $controller = new Photos_Controller(); $root = ORM::factory("item", 1); - $this->_photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test", "test", "test"); + $this->_photo = photo::create( + $root, MODPATH . "gallery/tests/test.jpg", "test.jpg", "test", "test"); $_POST["name"] = "new name"; $_POST["title"] = "new title"; $_POST["description"] = "new description"; -- cgit v1.2.3 From 2c30dc2d5b451ebd5623becd71c42b43be91d0b9 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 2 Sep 2009 14:28:00 -0700 Subject: fix a leading space that was causing the file_structure_test to fail --- modules/gallery/controllers/albums.php | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'modules') diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 8ceff0f9..627ee052 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -1,22 +1,22 @@ - Date: Wed, 2 Sep 2009 15:29:00 -0700 Subject: Change graphics::generate() API so that it doesn't return a boolean, instead it throws an exception if there's a problem. The normal case for graphics::generate is that it's going to succeed. It'll only fail if something un-handleable went wrong, so just use the resulting exception. --- modules/gallery/helpers/gallery_task.php | 11 ++++++----- modules/gallery/helpers/graphics.php | 10 ++++------ modules/gallery/helpers/photo.php | 6 ++++-- 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index c9557324..1b56ab97 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -60,14 +60,15 @@ class gallery_task_Core { $item = ORM::factory("item", $row->id); if ($item->loaded) { - $success = graphics::generate($item); - if (!$success) { + try { + graphics::generate($item); $ignored[$item->id] = 1; - $errors[] = t("Unable to rebuild images for '%title'", - array("title" => html::purify($item->title))); - } else { $errors[] = t("Successfully rebuilt images for '%title'", array("title" => html::purify($item->title))); + } catch (Exception $e) { + $errors[] = t("Unable to rebuild images for '%title'", + array("title" => html::purify($item->title))); + $errors[] = $e->__toString(); } } diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 66182a68..78812794 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -102,12 +102,12 @@ class graphics_Core { /** * Rebuild the thumb and resize for the given item. * @param Item_Model $item - * @return true on successful generation */ static function generate($item) { if ($item->is_album()) { if (!$cover = $item->album_cover()) { - return false; + // This album has no cover; there's nothing to generate. + return; } $input_file = $cover->file_path(); $input_item = $cover; @@ -127,7 +127,7 @@ class graphics_Core { $item->thumb_dirty = 0; $item->resize_dirty = 0; $item->save(); - return true; + return; } try { @@ -176,10 +176,8 @@ class graphics_Core { // @todo we should handle this better. Kohana::log("error", "Caught exception rebuilding image: {$item->title}\n" . $e->getMessage() . "\n" . $e->getTraceAsString()); - return false; + throw $e; } - - return true; } /** diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index 96a66d29..40b645a2 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -111,9 +111,11 @@ class photo_Core { // Build our thumbnail/resizes. If we fail to build thumbnail/resize we assume that the image // is bad in some way and discard it. - if (!graphics::generate($photo)) { + try { + graphics::generate($photo); + } catch (Exception $e) { $photo->delete(); - throw new Exception("@todo BAD_IMAGE_FILE"); + throw $e; } // If the parent has no cover item, make this it. -- cgit v1.2.3 From d007f31686e182e65cd18806ad3e4e29614fec81 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 21:29:22 -0700 Subject: Undo rest of the indentation issue accidentally created in 8312eb and partially fixed in 2c30dc --- modules/gallery/controllers/albums.php | 192 ++++++++++++++++----------------- 1 file changed, 96 insertions(+), 96 deletions(-) (limited to 'modules') diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 627ee052..5f62f798 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -17,102 +17,102 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - class Albums_Controller extends Items_Controller { - - /** - * @see REST_Controller::_show($resource) - */ - public function _show($album) { - $page_size = module::get_var("gallery", "page_size", 9); - if (!access::can("view", $album)) { - if ($album->id == 1) { - $view = new Theme_View("page.html", "login"); - $view->page_title = t("Log in to Gallery"); - $view->content = user::get_login_form("login/auth_html"); - print $view; - return; - } else { - access::forbidden(); - } - } - - $show = $this->input->get("show"); - - if ($show) { - $index = $album->get_position($show); - $page = ceil($index / $page_size); - if ($page == 1) { - url::redirect("albums/$album->id"); - } else { - url::redirect("albums/$album->id?page=$page"); - } - } - - $page = $this->input->get("page", "1"); - $children_count = $album->viewable()->children_count(); - $offset = ($page - 1) * $page_size; - $max_pages = max(ceil($children_count / $page_size), 1); - - // Make sure that the page references a valid offset - if ($page < 1) { - url::redirect("albums/$album->id"); - } else if ($page > $max_pages) { - url::redirect("albums/$album->id?page=$max_pages"); - } - - $template = new Theme_View("page.html", "album"); - $template->set_global("page_size", $page_size); - $template->set_global("item", $album); - $template->set_global("children", $album->viewable()->children($page_size, $offset)); - $template->set_global("children_count", $children_count); - $template->set_global("parents", $album->parents()); - $template->content = new View("album.html"); - - // We can't use math in ORM or the query builder, so do this by hand. It's important - // that we do this with math, otherwise concurrent accesses will damage accuracy. - Database::instance()->query( - "UPDATE {items} SET `view_count` = `view_count` + 1 WHERE `id` = $album->id"); - - print $template; - } - - /** - * @see REST_Controller::_create($resource) - */ - public function _create($album) { - access::verify_csrf(); - access::required("view", $album); - access::required("add", $album); - - switch ($this->input->post("type")) { - case "album": - return $this->_create_album($album); - - case "photo": - return $this->_create_photo($album); - - default: - access::forbidden(); - } - } - - private function _create_album($album) { - access::required("view", $album); - access::required("add", $album); - - $form = album::get_add_form($album); - if ($form->validate()) { - $new_album = album::create( - $album, - $this->input->post("name"), - $this->input->post("title", $this->input->post("name")), - $this->input->post("description"), - user::active()->id); - - log::success("content", "Created an album", - html::anchor("albums/$new_album->id", "view album")); - message::success(t("Created album %album_title", - array("album_title" => html::purify($new_album->title)))); +class Albums_Controller extends Items_Controller { + + /** + * @see REST_Controller::_show($resource) + */ + public function _show($album) { + $page_size = module::get_var("gallery", "page_size", 9); + if (!access::can("view", $album)) { + if ($album->id == 1) { + $view = new Theme_View("page.html", "login"); + $view->page_title = t("Log in to Gallery"); + $view->content = user::get_login_form("login/auth_html"); + print $view; + return; + } else { + access::forbidden(); + } + } + + $show = $this->input->get("show"); + + if ($show) { + $index = $album->get_position($show); + $page = ceil($index / $page_size); + if ($page == 1) { + url::redirect("albums/$album->id"); + } else { + url::redirect("albums/$album->id?page=$page"); + } + } + + $page = $this->input->get("page", "1"); + $children_count = $album->viewable()->children_count(); + $offset = ($page - 1) * $page_size; + $max_pages = max(ceil($children_count / $page_size), 1); + + // Make sure that the page references a valid offset + if ($page < 1) { + url::redirect("albums/$album->id"); + } else if ($page > $max_pages) { + url::redirect("albums/$album->id?page=$max_pages"); + } + + $template = new Theme_View("page.html", "album"); + $template->set_global("page_size", $page_size); + $template->set_global("item", $album); + $template->set_global("children", $album->viewable()->children($page_size, $offset)); + $template->set_global("children_count", $children_count); + $template->set_global("parents", $album->parents()); + $template->content = new View("album.html"); + + // We can't use math in ORM or the query builder, so do this by hand. It's important + // that we do this with math, otherwise concurrent accesses will damage accuracy. + Database::instance()->query( + "UPDATE {items} SET `view_count` = `view_count` + 1 WHERE `id` = $album->id"); + + print $template; + } + + /** + * @see REST_Controller::_create($resource) + */ + public function _create($album) { + access::verify_csrf(); + access::required("view", $album); + access::required("add", $album); + + switch ($this->input->post("type")) { + case "album": + return $this->_create_album($album); + + case "photo": + return $this->_create_photo($album); + + default: + access::forbidden(); + } + } + + private function _create_album($album) { + access::required("view", $album); + access::required("add", $album); + + $form = album::get_add_form($album); + if ($form->validate()) { + $new_album = album::create( + $album, + $this->input->post("name"), + $this->input->post("title", $this->input->post("name")), + $this->input->post("description"), + user::active()->id); + + log::success("content", "Created an album", + html::anchor("albums/$new_album->id", "view album")); + message::success(t("Created album %album_title", + array("album_title" => html::purify($new_album->title)))); print json_encode( array("result" => "success", -- cgit v1.2.3 From 02409d3b99fe7601cf5ed03d07b03112f2fe0c38 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Wed, 2 Sep 2009 22:35:54 -0600 Subject: Fix bg images in tables bug in webkit and ie. #718 --- modules/gallery/views/admin_maintenance.html.php | 8 ++-- themes/admin_default/css/screen.css | 47 ++++++++++++------------ 2 files changed, 27 insertions(+), 28 deletions(-) (limited to 'modules') diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index 4bca8653..ce693d73 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -7,7 +7,7 @@

      - +
      - "> + severity) ?>"> @@ -69,7 +69,7 @@ - "> + state == "stalled" ? "gWarning" : "" ?>"> @@ -142,7 +142,7 @@ - "> + state == "success" ? "gSuccess" : "gError" ?>"> diff --git a/themes/admin_default/css/screen.css b/themes/admin_default/css/screen.css index 24328133..c81db58d 100644 --- a/themes/admin_default/css/screen.css +++ b/themes/admin_default/css/screen.css @@ -356,48 +356,47 @@ li.gError select { .gInfo, .gSuccess, .gWarning { - background-position: .4em 50%; - background-repeat: no-repeat; padding: .4em .5em .4em 30px; } -.gError { - background-color: #f6cbca; - background-image: url('../images/ico-error.png'); +.gError, tr.gError td.gError { + background: #f6cbca url('../images/ico-error.png') no-repeat .4em 50%; } .gInfo { - background-color: #e8e8e8; - background-image: url('../images/ico-info.png'); + background: #e8e8e8 url('../images/ico-info.png') no-repeat .4em 50%; } .gSuccess { - background-color: #d9efc2; - background-image: url('../images/ico-success.png'); + background: #d9efc2 url('../images/ico-success.png') no-repeat .4em 50%; } -.gWarning { - background-color: #fcf9ce; - background-image: url('../images/ico-warning.png'); +.gWarning, tr.gWarning td.gWarning { + background: #fcf9ce url('../images/ico-warning.png') no-repeat .4em 50%; +} + +.gPager .gInfo, +tr.gError, +tr.gInfo, +tr.gSuccess, +tr.gWarning { + background: none; } -table .gError { - background-color: #f6cbca !important; +.gInfo td.gInfo { + background-color: transparent; } -table .gWarning { - background-color: #fcf9ce !important; +.gSuccess td.gSuccess { + background-color: transparent; } -.gPager .gInfo, -form .gError, -table .gInfo, -table .gSuccess { - background-color: transparent !important; +.gError td { + background-color: #f6cbca; } -.gPager .gInfo { - background-image: none !important; +.gWarning td { + background-color: #fcf9ce; } /* Inline layout (forms, lists) ~~~~~~~~~~ */ @@ -643,7 +642,7 @@ li.gGroup { li.gGroup h4 { background-color: #eee; - border-bottom: 1px dashed ccc; + border-bottom: 1px dashed #ccc; padding: .5em 0 .5em .5em; } li.gGroup .gButtonLink { -- cgit v1.2.3 From 33bcf11e2714f727f16136a1c09926cd5b6c8212 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 3 Sep 2009 01:05:03 -0700 Subject: Change the Html_Helper and SafeString tests to change the expeced results based on whether HtmlPurifier module is installed or not --- modules/gallery/tests/Html_Helper_Test.php | 5 +++-- modules/gallery/tests/SafeString_Test.php | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php index bfce6dcf..8f665e0c 100644 --- a/modules/gallery/tests/Html_Helper_Test.php +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -27,8 +27,9 @@ class Html_Helper_Test extends Unit_Test_Case { public function purify_test() { $safe_string = html::purify("hello

      world

      "); - $this->assert_equal("hello

      world

      ", - $safe_string); + $expected = + module::is_active("htmlpurifier") ? "hello

      world

      " : "hello <p >world</p>"; + $this->assert_equal($expected, $safe_string->unescaped()); $this->assert_true($safe_string instanceof SafeString); } diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 0895b7dd..37a1865f 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -91,7 +91,9 @@ class SafeString_Test extends Unit_Test_Case { public function purify_test() { $safe_string = SafeString::purify("hello

      world

      "); - $this->assert_equal("hello

      world

      ", $safe_string); + $expected = + module::is_active("htmlpurifier") ? "hello

      world

      " : "hello <p >world</p>"; + $this->assert_equal($expected, $safe_string->unescaped()); } public function of_fluid_api_test() { -- cgit v1.2.3 From 41e3773417a78949f44f463b28c41d55413c850b Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 3 Sep 2009 01:07:02 -0700 Subject: fix the expected return value of album controller --- modules/gallery/tests/Albums_Controller_Test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/tests/Albums_Controller_Test.php b/modules/gallery/tests/Albums_Controller_Test.php index 7674e85f..d65946c7 100644 --- a/modules/gallery/tests/Albums_Controller_Test.php +++ b/modules/gallery/tests/Albums_Controller_Test.php @@ -52,7 +52,7 @@ class Albums_Controller_Test extends Unit_Test_Case { ob_end_clean(); $this->assert_equal( - json_encode(array("result" => "success", "location" => "http://./index.php/test")), + json_encode(array("result" => "success")), $results); $this->assert_equal("new title", $this->_album->title); $this->assert_equal("new description", $this->_album->description); -- cgit v1.2.3 From dcdd44109b13a2cd2b29884edb6090e970178f32 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 3 Sep 2009 01:11:28 -0700 Subject: fix the expected return value of photos controller --- modules/gallery/tests/Photos_Controller_Test.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/Photos_Controller_Test.php b/modules/gallery/tests/Photos_Controller_Test.php index 5c4802c2..ac5ecdfd 100644 --- a/modules/gallery/tests/Photos_Controller_Test.php +++ b/modules/gallery/tests/Photos_Controller_Test.php @@ -50,8 +50,7 @@ class Photos_Controller_Test extends Unit_Test_Case { ob_end_clean(); $this->assert_equal( - json_encode(array("result" => "success", - "location" => "http://./index.php/test.jpeg")), + json_encode(array("result" => "success")), $results); $this->assert_equal("new title", $this->_photo->title); $this->assert_equal("new description", $this->_photo->description); -- cgit v1.2.3 From 8f6a120b52360475859c361514500e46698f0e74 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Thu, 3 Sep 2009 08:39:44 -0700 Subject: Ensure that purify isn't applied twice for an already purified SafeString --- modules/gallery/libraries/SafeString.php | 6 +++++- modules/gallery/tests/SafeString_Test.php | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 800647fa..e6f54add 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -51,7 +51,11 @@ class SafeString_Core { */ static function purify($string) { if ($string instanceof SafeString) { - $string = $string->unescaped(); + if ($string->_is_purified_html) { + return $string; + } else { + $string = $string->unescaped(); + } } $safe_string = self::of_safe_html(self::_purify_for_html($string)); $safe_string->_is_purified_html = true; diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 37a1865f..57ac87b9 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -93,7 +93,15 @@ class SafeString_Test extends Unit_Test_Case { $safe_string = SafeString::purify("hello

      world

      "); $expected = module::is_active("htmlpurifier") ? "hello

      world

      " : "hello <p >world</p>"; - $this->assert_equal($expected, $safe_string->unescaped()); + $this->assert_equal($expected, $safe_string); + } + + public function purify_twice_test() { + $safe_string = SafeString::purify("hello

      world

      "); + $safe_string_2 = SafeString::purify($safe_string); + $expected = + module::is_active("htmlpurifier") ? "hello

      world

      " : "hello <p >world</p>"; + $this->assert_equal($expected, $safe_string_2); } public function of_fluid_api_test() { -- cgit v1.2.3 From e2d5944e56f7e7433e7f1bda290ba779df447c3c Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Thu, 3 Sep 2009 08:49:14 -0700 Subject: Minor performance improvement: Reduce module var cache lookups in SafeString. --- modules/gallery/libraries/SafeString.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index e6f54add..93905572 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -158,8 +158,8 @@ class SafeString_Core { // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. private static function _purify_for_html($dirty_html) { - if (module::is_active("htmlpurifier")) { - if (empty(self::$_purifier)) { + if (null === self::$_purifier) { + if (module::is_active("htmlpurifier")) { require_once(MODPATH . "htmlpurifier/lib/HTMLPurifier/HTMLPurifier.auto.php"); $config = HTMLPurifier_Config::createDefault(); foreach (Kohana::config('purifier') as $category => $key_value) { @@ -168,7 +168,11 @@ class SafeString_Core { } } self::$_purifier = new HTMLPurifier($config); + } else { + self::$_purifier = false; } + } + if (self::$_purifier) { return self::$_purifier->purify($dirty_html); } else { return self::_escape_for_html($dirty_html); -- cgit v1.2.3 From 82dd468002d5d21a5c8c391d6fce543b3df43de1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:25:02 -0700 Subject: Refactor interaction with the purifier module so that the API is cleaner and we don't need to know about the module innards. Move the config file over there too. --- modules/gallery/config/purifier.php | 27 --------------------------- modules/gallery/libraries/SafeString.php | 28 ++++++++-------------------- 2 files changed, 8 insertions(+), 47 deletions(-) delete mode 100644 modules/gallery/config/purifier.php (limited to 'modules') diff --git a/modules/gallery/config/purifier.php b/modules/gallery/config/purifier.php deleted file mode 100644 index 30de9dc5..00000000 --- a/modules/gallery/config/purifier.php +++ /dev/null @@ -1,27 +0,0 @@ - TMPPATH -); - -$config["Attr"] = array( - "EnableID" => true -); diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 93905572..3328fed5 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -26,8 +26,6 @@ class SafeString_Core { protected $_is_safe_html = false; protected $_is_purified_html = false; - private static $_purifier = null; - /** Constructor */ function __construct($string) { if ($string instanceof SafeString) { @@ -151,29 +149,19 @@ class SafeString_Core { return $this->_raw_string; } - // Escapes special HTML chars ("<", ">", "&", etc.) to HTML entities. + /** + * Escape special HTML chars ("<", ">", "&", etc.) to HTML entities. + */ private static function _escape_for_html($dirty_html) { return html::specialchars($dirty_html); } - // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. + /** + * Purify the string, removing any potentially malicious or unsafe HTML / JavaScript. + */ private static function _purify_for_html($dirty_html) { - if (null === self::$_purifier) { - if (module::is_active("htmlpurifier")) { - require_once(MODPATH . "htmlpurifier/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); - } else { - self::$_purifier = false; - } - } - if (self::$_purifier) { - return self::$_purifier->purify($dirty_html); + if (method_exists("purifier", "purify")) { + return purifier::purify($dirty_html); } else { return self::_escape_for_html($dirty_html); } -- cgit v1.2.3 From 1dca0b9d6be5a96e79e3de776e231e21ed824589 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:28:42 -0700 Subject: Fix test for new purifier API. --- modules/gallery/tests/Html_Helper_Test.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php index 8f665e0c..1662b866 100644 --- a/modules/gallery/tests/Html_Helper_Test.php +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -27,8 +27,9 @@ class Html_Helper_Test extends Unit_Test_Case { public function purify_test() { $safe_string = html::purify("hello

      world

      "); - $expected = - module::is_active("htmlpurifier") ? "hello

      world

      " : "hello <p >world</p>"; + $expected = method_exists("purifier", "purify") + ? "hello

      world

      " + : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string->unescaped()); $this->assert_true($safe_string instanceof SafeString); } -- cgit v1.2.3 From 1405e8ed9e2003d1b06853bae4ce3413de1910ce Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:29:57 -0700 Subject: Fix tests for new purifier API. --- modules/gallery/tests/SafeString_Test.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 57ac87b9..fdab5c58 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -91,16 +91,18 @@ class SafeString_Test extends Unit_Test_Case { public function purify_test() { $safe_string = SafeString::purify("hello

      world

      "); - $expected = - module::is_active("htmlpurifier") ? "hello

      world

      " : "hello <p >world</p>"; + $expected = method_exists("purifier", "purify") + ? "hello

      world

      " + : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string); } public function purify_twice_test() { $safe_string = SafeString::purify("hello

      world

      "); $safe_string_2 = SafeString::purify($safe_string); - $expected = - module::is_active("htmlpurifier") ? "hello

      world

      " : "hello <p >world</p>"; + $expected = method_exists("purifier", "purify") + ? "hello

      world

      " + : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string_2); } -- cgit v1.2.3 From 1ffb5b24dff439b4a3e9e7f2df3af1a0f8e9e5a0 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:34:02 -0700 Subject: Checkpoint. --- modules/gallery/tests/xss_data.txt | 40 ++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 7e536e90..00eba901 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -71,19 +71,19 @@ modules/gallery/views/admin_languages.html.php 28 DIRTY form:: modules/gallery/views/admin_languages.html.php 29 DIRTY $display_name modules/gallery/views/admin_languages.html.php 31 DIRTY form::radio("default_locale",$code,($default_locale==$code),((isset($installed_locales[$code]))?'':'disabled="disabled"')) modules/gallery/views/admin_languages.html.php 102 DIRTY $share_translations_form -modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR ($i%2==0)?"gOddRow":"gEvenRow" +modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 25 DIRTY_ATTR log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 26 DIRTY $task->name modules/gallery/views/admin_maintenance.html.php 29 DIRTY $task->description -modules/gallery/views/admin_maintenance.html.php 72 DIRTY_ATTR $task->state=="stalled"?"gWarning":"" modules/gallery/views/admin_maintenance.html.php 72 DIRTY_ATTR ($i%2==0)?"gOddRow":"gEvenRow" +modules/gallery/views/admin_maintenance.html.php 72 DIRTY_ATTR $task->state=="stalled"?"gWarning":"" modules/gallery/views/admin_maintenance.html.php 73 DIRTY_ATTR $task->state=="stalled"?"gWarning":"" modules/gallery/views/admin_maintenance.html.php 74 DIRTY gallery::date_time($task->updated) modules/gallery/views/admin_maintenance.html.php 77 DIRTY $task->name modules/gallery/views/admin_maintenance.html.php 92 DIRTY $task->status -modules/gallery/views/admin_maintenance.html.php 145 DIRTY_ATTR $task->state=="success"?"gSuccess":"gError" modules/gallery/views/admin_maintenance.html.php 145 DIRTY_ATTR ($i%2==0)?"gOddRow":"gEvenRow" +modules/gallery/views/admin_maintenance.html.php 145 DIRTY_ATTR $task->state=="success"?"gSuccess":"gError" modules/gallery/views/admin_maintenance.html.php 146 DIRTY_ATTR $task->state=="success"?"gSuccess":"gError" modules/gallery/views/admin_maintenance.html.php 147 DIRTY gallery::date_time($task->updated) modules/gallery/views/admin_maintenance.html.php 150 DIRTY $task->name @@ -142,11 +142,11 @@ modules/gallery/views/movieplayer.html.php 7 DIRTY_JS url::a modules/gallery/views/movieplayer.html.php 13 DIRTY_JS url::abs_file("lib/flowplayer.h264streaming.swf") modules/gallery/views/permissions_browse.html.php 3 DIRTY_JS url::site("permissions/form/__ITEM__") modules/gallery/views/permissions_browse.html.php 16 DIRTY_JS url::site("permissions/change/__CMD__/__GROUP__/__PERM__/__ITEM__?csrf=$csrf") -modules/gallery/views/permissions_browse.html.php 41 DIRTY_ATTR $parent->id -modules/gallery/views/permissions_browse.html.php 42 DIRTY_JS $parent->id -modules/gallery/views/permissions_browse.html.php 47 DIRTY_ATTR $item->id -modules/gallery/views/permissions_browse.html.php 48 DIRTY_JS $item->id -modules/gallery/views/permissions_browse.html.php 55 DIRTY $form +modules/gallery/views/permissions_browse.html.php 42 DIRTY_ATTR $parent->id +modules/gallery/views/permissions_browse.html.php 43 DIRTY_JS $parent->id +modules/gallery/views/permissions_browse.html.php 48 DIRTY_ATTR $item->id +modules/gallery/views/permissions_browse.html.php 49 DIRTY_JS $item->id +modules/gallery/views/permissions_browse.html.php 56 DIRTY $form modules/gallery/views/permissions_form.html.php 24 DIRTY_JS $lock->id modules/gallery/views/permissions_form.html.php 32 DIRTY_JS $group->id modules/gallery/views/permissions_form.html.php 32 DIRTY_JS $permission->id @@ -280,17 +280,17 @@ modules/user/views/login_ajax.html.php 37 DIRTY $form modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $width modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $height modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $url -themes/admin_default/views/admin.html.php 16 DIRTY_JS $theme->url() -themes/admin_default/views/admin.html.php 34 DIRTY $theme->admin_head() -themes/admin_default/views/admin.html.php 38 DIRTY $theme->admin_page_top() -themes/admin_default/views/admin.html.php 46 DIRTY $theme->admin_header_top() -themes/admin_default/views/admin.html.php 55 DIRTY $theme->admin_menu() -themes/admin_default/views/admin.html.php 57 DIRTY $theme->admin_header_bottom() -themes/admin_default/views/admin.html.php 64 DIRTY $content -themes/admin_default/views/admin.html.php 70 DIRTY $sidebar -themes/admin_default/views/admin.html.php 75 DIRTY $theme->admin_footer() -themes/admin_default/views/admin.html.php 77 DIRTY $theme->admin_credits() -themes/admin_default/views/admin.html.php 81 DIRTY $theme->admin_page_bottom() +themes/admin_default/views/admin.html.php 15 DIRTY_JS $theme->url() +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 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 +themes/admin_default/views/admin.html.php 68 DIRTY $sidebar +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 @@ -319,13 +319,11 @@ themes/default/views/movie.html.php 8 DIRTY_JS $previ themes/default/views/movie.html.php 18 DIRTY_JS $next_item->url() themes/default/views/movie.html.php 28 DIRTY $item->movie_img(array("class"=>"gMovie","id"=>"gMovieId-{$item->id}")) themes/default/views/page.html.php 9 DIRTY $page_title -themes/default/views/page.html.php 26 DIRTY_JS $theme->url() themes/default/views/page.html.php 32 DIRTY_JS $theme->url() themes/default/views/page.html.php 41 DIRTY $new_width 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 85 DIRTY_ATTR $theme->url() 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 -- cgit v1.2.3 From c453c0ef8239bc79e484dd3feb9e275e942e9d48 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 10:11:42 -0700 Subject: Simplifying SafeString a bit: From a XSS HTML security point of view, treat clean() and purify() the same. No longer run a safe HTML string through the HTML purifier (since it's already marked as safe). This also addresses the issue of calling purify() when no purifier is installed. In that case, we'd run clean() on a clean string (double HTML encoding). If this approach doesn't work out, we can still modify the fallback code of purify() to check if the string is already clean before calling clean() instead of purify(). --- modules/gallery/libraries/SafeString.php | 11 ++--------- modules/gallery/tests/SafeString_Test.php | 6 ++++++ 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'modules') diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 3328fed5..ba3a8ffd 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -24,13 +24,11 @@ class SafeString_Core { private $_raw_string; protected $_is_safe_html = false; - protected $_is_purified_html = false; /** 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; @@ -49,14 +47,13 @@ class SafeString_Core { */ static function purify($string) { if ($string instanceof SafeString) { - if ($string->_is_purified_html) { + if ($string->_is_safe_html) { return $string; } else { $string = $string->unescaped(); } } $safe_string = self::of_safe_html(self::_purify_for_html($string)); - $safe_string->_is_purified_html = true; return $safe_string; } @@ -135,11 +132,7 @@ class SafeString_Core { * @return the string escaped for use in HTML. */ function purified_html() { - if ($this->_is_purified_html) { - return $this; - } else { - return self::purify($this); - } + return self::purify($this); } /** diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index fdab5c58..2c07d934 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -106,6 +106,12 @@ class SafeString_Test extends Unit_Test_Case { $this->assert_equal($expected, $safe_string_2); } + public function purify_safe_html_test() { + $safe_string = SafeString::of_safe_html("hello

      world

      "); + $actual = SafeString::purify($safe_string); + $this->assert_equal("hello

      world

      ", $actual); + } + public function of_fluid_api_test() { $escaped_string = SafeString::of("Foo's bar")->for_js(); $this->assert_equal('"Foo\'s bar"', $escaped_string); -- cgit v1.2.3 From 001623c755777846a468255d4396d30b253dcdfb Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 11:06:20 -0700 Subject: Add new locale preferences: Adding per session (cookie) locale preferences and check the browser's / OS' locale preferences. Ticket 582. --- modules/gallery/helpers/locales.php | 85 +++++++++++++++++++++++++++++++++++++ modules/user/helpers/user.php | 18 ++++++++ modules/user/helpers/user_event.php | 24 ++++++++--- modules/user/helpers/user_theme.php | 24 +++++++++++ 4 files changed, 145 insertions(+), 6 deletions(-) (limited to 'modules') diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index 3762b97b..1320c155 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -23,6 +23,7 @@ */ class locales_Core { private static $locales; + private static $language_subtag_to_locale; /** * Return the list of available locales. @@ -105,6 +106,16 @@ class locales_Core { $l["zh_TW"] = "繁體中文"; // Chinese (TW) asort($l, SORT_LOCALE_STRING); self::$locales = $l; + + // Language subtag to (default) locale mapping + foreach ($l as $locale => $name) { + list ($language) = explode("_", $locale . "_"); + // The first one mentioned is the default + if (!isset($d[$language])) { + $d[$language] = $locale; + } + } + self::$language_subtag_to_locale = $d; } static function display_name($locale=null) { @@ -121,4 +132,78 @@ class locales_Core { list ($language, $territory) = explode('_', $locale . "_"); return in_array($language, array("he", "fa", "ar")); } + + /** + * Returns the best match comparing the HTTP accept-language header + * with the installed locales. + */ + static function locale_from_http_request() { + $http_accept_language = Input::instance()->server("HTTP_ACCEPT_LANGUAGE"); + if ($http_accept_language) { + // Parse the HTTP header and build a preference list + // Example value: "de,en-us;q=0.7,en-uk,fr-fr;q=0.2" + $locale_preferences = array(); + foreach (explode(",", $http_accept_language) as $code) { + list ($requested_locale, $qvalue) = explode(";", $code . ";"); + $requested_locale = trim($requested_locale); + $qvalue = trim($qvalue); + if (preg_match("/^([a-z]{2,3})(?:[_-]([a-zA-Z]{2}))?/", $requested_locale, $matches)) { + $requested_locale = strtolower($matches[1]); + if (!empty($matches[2])) { + $requested_locale .= "_" . strtoupper($matches[2]); + } + $requested_locale = trim(str_replace("-", "_", $requested_locale)); + if (!strlen($qvalue)) { + // If not specified, default to 1. + $qvalue = 1; + } else { + // qvalue is expected to be something like "q=0.7" + list ($ignored, $qvalue) = explode("=", $qvalue . "=="); + $qvalue = floatval($qvalue); + } + $locale_preferences[] = array($requested_locale, $qvalue); + } + } + + // Compare and score requested locales with installed ones + $matched_locales = array(); + foreach ($locale_preferences as $requested_value) { + $scored_locale_match = self::_locale_match_score($requested_value); + if ($scored_locale_match) { + $scored_locales[] = $scored_locale_match; + } + } + + usort($matched_locales, array("locales", "_compare_locale_by_qvalue")); + + $best_match = array_shift($scored_locales); + if ($best_match) { + return $best_match[0]; + } + } + + return null; + } + + static function _compare_locale_by_qvalue($a, $b) { + $a = $a[1]; + $b = $b[1]; + if ($a == $b) { + return 0; + } + return $a < $b ? 1 : -1; + } + + private static function _locale_match_score($requested_locale_and_qvalue) { + list ($requested_locale, $qvalue) = $requested_locale_and_qvalue; + $installed = self::installed(); + if (isset($installed[$requested_locale])) { + return $requested_locale_and_qvalue; + } + list ($language) = explode("_", $requested_locale . "_"); + if (isset(self::$language_subtag_to_locale[$language])) { + return array(self::$language_subtag_to_locale[$language], $qvalue * 0.66); + } + return null; + } } \ No newline at end of file diff --git a/modules/user/helpers/user.php b/modules/user/helpers/user.php index 40acc2ec..b9162b92 100644 --- a/modules/user/helpers/user.php +++ b/modules/user/helpers/user.php @@ -87,6 +87,9 @@ class user_Core { private static function _add_locale_dropdown(&$form, $user=null) { $locales = locales::installed(); + foreach ($locales as $locale => $display_name) { + $locales[$locale] = SafeString::of_safe_html($display_name); + } if (count($locales) > 1) { // Put "none" at the first position in the array $locales = array_merge(array("" => t("« none »")), $locales); @@ -336,4 +339,19 @@ class user_Core { } return $salt . md5($salt . $password); } + + static function cookie_locale() { + $cookie_data = Input::instance()->cookie("g_locale"); + $locale = null; + if ($cookie_data) { + if (preg_match("/^([a-z]{2,3}(?:_[A-Z]{2})?)$/", trim($cookie_data), $matches)) { + $requested_locale = $matches[1]; + $installed_locales = locales::installed(); + if (isset($installed_locales[$requested_locale])) { + $locale = $requested_locale; + } + } + } + return $locale; + } } \ No newline at end of file diff --git a/modules/user/helpers/user_event.php b/modules/user/helpers/user_event.php index 4bde224b..ede4e515 100644 --- a/modules/user/helpers/user_event.php +++ b/modules/user/helpers/user_event.php @@ -23,12 +23,7 @@ class user_event_Core { */ static function gallery_ready() { user::load_user(); - - $locale = user::active()->locale; - if (!empty($locale)) { - // TODO(andy_st): Check session data as well. - I18n::instance()->locale($locale); - } + self::set_request_locale(); } static function admin_menu($menu, $theme) { @@ -38,4 +33,21 @@ class user_event_Core { ->label(t("Users/Groups")) ->url(url::site("admin/users"))); } + + static function set_request_locale() { + // 1. Check the session specific preference (cookie) + $locale = user::cookie_locale(); + // 2. Check the user's preference + if (!$locale) { + $locale = user::active()->locale; + } + // 3. Check the browser's / OS' preference + if (!$locale) { + $locale = locales::locale_from_http_request(); + } + // If we have any preference, override the site's default locale + if ($locale) { + I18n::instance()->locale($locale); + } + } } diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 8de2d248..5b973ef3 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -18,6 +18,14 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class user_theme_Core { + static function head($theme) { + if (count(locales::installed())) { + // Needed by the languages block + $theme->script("jquery.cookie.js"); + } + return ""; + } + static function header_top($theme) { if ($theme->page_type != "login") { $view = new View("login.html"); @@ -25,4 +33,20 @@ class user_theme_Core { return $view->render(); } } + + static function sidebar_blocks($theme) { + $locales = locales::installed(); + foreach ($locales as $locale => $display_name) { + $locales[$locale] = SafeString::of_safe_html($display_name); + } + if (count($locales) > 1) { + $block = new Block(); + $block->css_id = "gUserLanguageBlock"; + $block->title = t("Select Language Preference"); + $block->content = new View("user_languages_block.html"); + $block->content->installed_locales = array_merge(array("" => t("« none »")), $locales); + $block->content->selected = (string) user::cookie_locale(); + return $block; + } + } } -- cgit v1.2.3 From 75e99c9ea33fa5723dec9a2f5250e8bb38755718 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 11:17:11 -0700 Subject: When changing user preferences, reset the session based locale preferences. --- modules/user/controllers/users.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/user/controllers/users.php b/modules/user/controllers/users.php index 0bf2e81d..4ad704f0 100644 --- a/modules/user/controllers/users.php +++ b/modules/user/controllers/users.php @@ -36,7 +36,12 @@ class Users_Controller extends REST_Controller { $user->url = $form->edit_user->url->value; if ($form->edit_user->locale) { $desired_locale = $form->edit_user->locale->value; - $user->locale = $desired_locale == "none" ? null : $desired_locale; + $new_locale = $desired_locale == "none" ? null : $desired_locale; + if ($new_locale != $user->locale) { + // Delete the session based locale preference + setcookie("g_locale", "", time() - 24 * 3600, "/"); + } + $user->locale = $new_locale; } $user->save(); module::event("user_edit_form_completed", $user, $form); -- cgit v1.2.3 From f63766556a701c173f578caea58597ea7febb865 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 11:20:02 -0700 Subject: XSS test golden data file update --- modules/gallery/tests/xss_data.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'modules') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 00eba901..a1a708df 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -277,6 +277,7 @@ modules/user/views/admin_users_group.html.php 22 DIRTY_JS $user- modules/user/views/admin_users_group.html.php 22 DIRTY_JS $group->id modules/user/views/login_ajax.html.php 6 DIRTY_JS url::site("password/reset") modules/user/views/login_ajax.html.php 37 DIRTY $form +modules/user/views/user_languages_block.html.php 2 DIRTY form::dropdown("gSelectSessionLocale",$installed_locales,$selected) modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $width modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $height modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $url -- cgit v1.2.3 From 49de9bba68dd466dadd3c4df3d5024b3820568ff Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:19:15 -0700 Subject: Add @todo to replace locales::locale_from_http_request() request::accepts_language() when we upgrade to Kohana 2.4 --- modules/gallery/helpers/locales.php | 1 + 1 file changed, 1 insertion(+) (limited to 'modules') diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index 1320c155..04fa8954 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -136,6 +136,7 @@ class locales_Core { /** * Returns the best match comparing the HTTP accept-language header * with the installed locales. + * @todo replace this with request::accepts_language() when we upgrade to Kohana 2.4 */ static function locale_from_http_request() { $http_accept_language = Input::instance()->server("HTTP_ACCEPT_LANGUAGE"); -- cgit v1.2.3 From a25640f9b26c75e14109f07fcc4863adc300f062 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:28:46 -0700 Subject: Shorten the name in the block so that it doesn't wrap. Use « and » in the << none >> text. --- modules/user/helpers/user_theme.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 5b973ef3..184a2bc9 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -42,9 +42,10 @@ class user_theme_Core { if (count($locales) > 1) { $block = new Block(); $block->css_id = "gUserLanguageBlock"; - $block->title = t("Select Language Preference"); + $block->title = t("Language Preference"); $block->content = new View("user_languages_block.html"); - $block->content->installed_locales = array_merge(array("" => t("« none »")), $locales); + $block->content->installed_locales = + array_merge(array("" => t("« none »")), $locales); $block->content->selected = (string) user::cookie_locale(); return $block; } -- cgit v1.2.3 From add134cc75214c3852566ae27e5eb7b35c59c53e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:29:12 -0700 Subject: placeholder for a missing view --- modules/user/views/user_languages_block.html.php | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 modules/user/views/user_languages_block.html.php (limited to 'modules') diff --git a/modules/user/views/user_languages_block.html.php b/modules/user/views/user_languages_block.html.php new file mode 100644 index 00000000..c422f55c --- /dev/null +++ b/modules/user/views/user_languages_block.html.php @@ -0,0 +1,2 @@ + + -- cgit v1.2.3 From ab7323d17b3c3e445fb51d7b4330e89b4e16aaa9 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 21:27:23 -0700 Subject: Fix the url in the call to get subsequent entries to have the right url, and to be json. Fixes #719, which I introduced in my refactor. --- modules/organize/views/organize_thumb_grid.html.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'modules') diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index 929d9ec3..af7136fc 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -11,12 +11,13 @@ children_count() > $offset): ?> -- cgit v1.2.3 From 9fbdcf3efd37e2c6bf67b197b8c93f8790a79cbe Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 5 Sep 2009 13:39:30 -0700 Subject: Change the module installer so that you don't need to provide your own install() function if all you're going to do is to set the version of the module from module.info into the database. This means that for some simple modules, you don't need an install.php file at all. --- modules/akismet/helpers/akismet_installer.php | 4 ---- modules/gallery/helpers/module.php | 9 ++++++++ .../image_block/helpers/image_block_installer.php | 24 ---------------------- modules/info/helpers/info_installer.php | 24 ---------------------- modules/organize/helpers/organize_installer.php | 24 ---------------------- modules/recaptcha/helpers/recaptcha_installer.php | 4 ---- modules/rss/helpers/rss_installer.php | 24 ---------------------- modules/slideshow/helpers/slideshow_installer.php | 4 ---- 8 files changed, 9 insertions(+), 108 deletions(-) delete mode 100644 modules/image_block/helpers/image_block_installer.php delete mode 100644 modules/info/helpers/info_installer.php delete mode 100644 modules/organize/helpers/organize_installer.php delete mode 100644 modules/rss/helpers/rss_installer.php (limited to 'modules') diff --git a/modules/akismet/helpers/akismet_installer.php b/modules/akismet/helpers/akismet_installer.php index 5d8c0e07..b891fc7b 100644 --- a/modules/akismet/helpers/akismet_installer.php +++ b/modules/akismet/helpers/akismet_installer.php @@ -18,10 +18,6 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class akismet_installer { - static function install() { - module::set_version("akismet", 1); - } - static function activate() { akismet::check_config(); } diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index 03d538a9..a3088c38 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -119,6 +119,8 @@ class module_Core { $installer_class = "{$module_name}_installer"; if (method_exists($installer_class, "install")) { call_user_func_array(array($installer_class, "install"), array()); + } else { + module::set_version($module_name, 1); } module::load_modules(); @@ -145,6 +147,13 @@ class module_Core { $installer_class = "{$module_name}_installer"; if (method_exists($installer_class, "upgrade")) { call_user_func_array(array($installer_class, "upgrade"), array($version_before)); + } else { + $available = module::available(); + if (isset($available->$module_name->code_version)) { + module::set_version($module_name, $available->$module_name->code_version); + } else { + throw new Exception("@todo UNKNOWN_MODULE"); + } } module::load_modules(); diff --git a/modules/image_block/helpers/image_block_installer.php b/modules/image_block/helpers/image_block_installer.php deleted file mode 100644 index 7ea6a229..00000000 --- a/modules/image_block/helpers/image_block_installer.php +++ /dev/null @@ -1,24 +0,0 @@ - Date: Sat, 5 Sep 2009 17:39:49 -0700 Subject: Add missing view for language selection --- modules/user/views/user_languages_block.html.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/user/views/user_languages_block.html.php b/modules/user/views/user_languages_block.html.php index c422f55c..df145bc0 100644 --- a/modules/user/views/user_languages_block.html.php +++ b/modules/user/views/user_languages_block.html.php @@ -1,2 +1,19 @@ - + + + -- cgit v1.2.3 From beb232a1cc6f081b432f32a72bddadcaf3f90df4 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 5 Sep 2009 17:43:47 -0700 Subject: Revert previous edit. Prefer « none » (sweet, nice Unicode characters) instead of HTML entities. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/user/helpers/user_theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 184a2bc9..098d87fd 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -45,7 +45,7 @@ class user_theme_Core { $block->title = t("Language Preference"); $block->content = new View("user_languages_block.html"); $block->content->installed_locales = - array_merge(array("" => t("« none »")), $locales); + array_merge(array("" => t("« none »")), $locales); $block->content->selected = (string) user::cookie_locale(); return $block; } -- cgit v1.2.3 From b01596c0f08f00e5fc2d1019b3905fe5fd76a223 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 5 Sep 2009 18:19:13 -0700 Subject: Update XSS test golden data file. --- modules/gallery/tests/xss_data.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index a1a708df..ffd69eb1 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -200,7 +200,7 @@ modules/organize/views/organize_thumb_grid.html.php 3 DIRTY_ATTR $chi modules/organize/views/organize_thumb_grid.html.php 4 DIRTY_ATTR $child->id modules/organize/views/organize_thumb_grid.html.php 5 DIRTY_ATTR $child->is_album()?"gAlbum":"gPhoto" modules/organize/views/organize_thumb_grid.html.php 6 DIRTY $child->thumb_img(array("class"=>"gThumbnail","ref"=>$child->id),90,true) -modules/organize/views/organize_thumb_grid.html.php 14 DIRTY_JS url::site("organize/content/$album->id/".($offset+25)) +modules/organize/views/organize_thumb_grid.html.php 14 DIRTY_JS url::site("organize/album/$album->id/".($offset+25)) modules/organize/views/organize_tree.html.php 2 DIRTY_ATTR access::can("edit",$album)?"":"gViewOnly" modules/organize/views/organize_tree.html.php 3 DIRTY_ATTR $album->id modules/organize/views/organize_tree.html.php 6 DIRTY_ATTR $selected&&$album->id==$selected->id?"selected":"" -- cgit v1.2.3 From b3d0cb5a4c88c42e29e67f3b3eb4e91151802164 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 5 Sep 2009 18:55:44 -0700 Subject: Bugfixes for locales::locale_from_http_request(), and adding tests. (And the tests should illustrate that kohana 2.4's API doesn't quite fit our purpose of simply getting the best match between the accepted (client) and the installed (g3) locales.) --- modules/gallery/helpers/locales.php | 10 +++- modules/gallery/tests/Locales_Helper_Test.php | 86 +++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 modules/gallery/tests/Locales_Helper_Test.php (limited to 'modules') diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index 04fa8954..16dda2d7 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -56,6 +56,9 @@ class locales_Core { : array_merge($locales, array($default)); module::set_var("gallery", "installed_locales", join("|", $locales)); + + // Clear the cache + self::$locales = null; } // @todo Might want to add a localizable language name as well. @@ -167,7 +170,7 @@ class locales_Core { } // Compare and score requested locales with installed ones - $matched_locales = array(); + $scored_locales = array(); foreach ($locale_preferences as $requested_value) { $scored_locale_match = self::_locale_match_score($requested_value); if ($scored_locale_match) { @@ -175,7 +178,7 @@ class locales_Core { } } - usort($matched_locales, array("locales", "_compare_locale_by_qvalue")); + usort($scored_locales, array("locales", "_compare_locale_by_qvalue")); $best_match = array_shift($scored_locales); if ($best_match) { @@ -202,7 +205,8 @@ class locales_Core { return $requested_locale_and_qvalue; } list ($language) = explode("_", $requested_locale . "_"); - if (isset(self::$language_subtag_to_locale[$language])) { + if (isset(self::$language_subtag_to_locale[$language]) && + isset($installed[self::$language_subtag_to_locale[$language]])) { return array(self::$language_subtag_to_locale[$language], $qvalue * 0.66); } return null; diff --git a/modules/gallery/tests/Locales_Helper_Test.php b/modules/gallery/tests/Locales_Helper_Test.php new file mode 100644 index 00000000..85b8e206 --- /dev/null +++ b/modules/gallery/tests/Locales_Helper_Test.php @@ -0,0 +1,86 @@ +assert_equal("de_DE", $locale); + } + + public function locale_from_http_request_fallback_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "de"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("de_DE", $locale); + } + + public function locale_from_http_request_by_qvalue_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "de-de;q=0.8,fr-fr;q=0.9"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("fr_FR", $locale); + } + + public function locale_from_http_request_default_qvalue_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "de-de;q=0.8,it-it,fr-fr;q=0.9"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("it_IT", $locale); + } + + public function locale_from_http_request_lang_fallback_qvalue_adjustment_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = ",fr-fr;q=0.4,de-ch;q=0.8"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("de_DE", $locale); + } + + public function locale_from_http_request_best_match_vs_installed_test() { + 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); + } + + public function locale_from_http_request_best_match_vs_installed_2_test() { + locales::update_installed(array("no_NO", "pt_PT", "ja_JP")); + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "en,en-us,ja_JP;q=0.5,no-fr;q=0.9"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("no_NO", $locale); + } + + public function locale_from_http_request_no_match_vs_installed_test() { + locales::update_installed(array("no_NO", "pt_PT", "ja_JP")); + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "en,en-us,de"; + $locale = locales::locale_from_http_request(); + $this->assert_equal(null, $locale); + } +} \ No newline at end of file -- cgit v1.2.3 From d8f5b0f5a30adb97d48fa49999c6ec7407666c44 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 5 Sep 2009 21:14:25 -0700 Subject: Change click() to change() so that we immediately update the UI when the user picks a new option. --- modules/user/views/user_languages_block.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/user/views/user_languages_block.html.php b/modules/user/views/user_languages_block.html.php index df145bc0..b5ae674c 100644 --- a/modules/user/views/user_languages_block.html.php +++ b/modules/user/views/user_languages_block.html.php @@ -1,7 +1,7 @@ -

      - -

      - Gallery website has news and information about the Gallery project and community.", array("url" => "http://gallery.menalto.com")) ?> -

      - -

      - documentation site or you can ask for help in the forums!", array("codex_url" => "http://codex.gallery2.org/Main_Page", "forum_url" => "http://gallery.menalto.com/forum")) ?> - diff --git a/modules/gallery/views/after_install_loader.html.php b/modules/gallery/views/after_install_loader.html.php deleted file mode 100644 index c2e3e1d9..00000000 --- a/modules/gallery/views/after_install_loader.html.php +++ /dev/null @@ -1,7 +0,0 @@ - -for_html_attr() ?>" - href=""/> - diff --git a/modules/gallery/views/welcome_message.html.php b/modules/gallery/views/welcome_message.html.php new file mode 100644 index 00000000..5515c3dc --- /dev/null +++ b/modules/gallery/views/welcome_message.html.php @@ -0,0 +1,36 @@ + +

      +

      + +

      + +

      +

      + +

      +

      + +

      + %user_name account. You should change your password to something that you'll remember.", array("user_name" => $user->name)) ?> +

      + +

      + id}") ?>" + title="for_html_attr() ?>" + id="gAfterInstallChangePasswordLink" + class="gButtonLink ui-state-default ui-corners-all"> + + + +

      + +

      + Gallery website has news and information about the Gallery project and community.", array("url" => "http://gallery.menalto.com")) ?> +

      + +

      + documentation site or you can ask for help in the forums!", array("codex_url" => "http://codex.gallery2.org/Main_Page", "forum_url" => "http://gallery.menalto.com/forum")) ?> +

      +
      diff --git a/modules/gallery/views/welcome_message_loader.html.php b/modules/gallery/views/welcome_message_loader.html.php new file mode 100644 index 00000000..2c6bffca --- /dev/null +++ b/modules/gallery/views/welcome_message_loader.html.php @@ -0,0 +1,7 @@ + +for_html_attr() ?>" + href=""/> + diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index fec618e6..d4c23155 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -773,6 +773,10 @@ form .gError, text-decoration: underline; } +#gWelcomeMessage p { + padding-bottom: 1em; +} + /* Pagination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ .gPager { -- cgit v1.2.3 From 190d7aaa55b4f55ea3d93fb8a3d4650d7e1fc85c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:12:15 -0700 Subject: Remove debug code. --- modules/gallery/helpers/gallery_theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php index 8c97f124..20dfeb04 100644 --- a/modules/gallery/helpers/gallery_theme.php +++ b/modules/gallery/helpers/gallery_theme.php @@ -70,7 +70,7 @@ class gallery_theme_Core { return L10n_Client_Controller::l10n_form(); } - if (true || $session->get("after_install")) { + if ($session->get("after_install")) { $session->delete("after_install"); return new View("welcome_message_loader.html"); } -- cgit v1.2.3 From 25ea6085b78423ee651dc21b639c5f10f59dcaf0 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 10 Sep 2009 21:26:07 -0700 Subject: Reset the margins when the mouse is over a thumbnail when dragging. When the border is displayed then adjust the margin to account for the border. Just hidding the border causes things to move. --- modules/organize/js/organize.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 0aeb4f7c..c30f89e0 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -122,12 +122,12 @@ mouse_move_handler: function(event) { if ($(".gDragHelper").length) { - $(".gOrganizeMicroThumbGridCell").css("borderStyle", "hidden"); + $(".gOrganizeMicroThumbGridCell").css({borderStyle: "hidden", margin: "4px"}); $(".currentDropTarget").removeClass("currentDropTarget"); var borderStyle = event.pageX < $(this).offset().left + $(this).width() / 2 ? - "borderLeftStyle" : "borderRightStyle"; + {borderLeftStyle: "solid", marginLeft: "2px"} : {borderRightStyle: "solid", marginRight: "2px"}; $(this).addClass("currentDropTarget") - .css(borderStyle, "solid"); + .css(borderStyle); } }, -- cgit v1.2.3 From 7fddd2aced1821f977323fc75f2954f2b240ae37 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:31:50 -0700 Subject: Use abs_url() inside url::redirect() calls so that we don't just wind up tacking onto the base url. --- modules/gallery/controllers/albums.php | 8 ++++---- modules/gallery/controllers/items.php | 2 +- modules/gallery/controllers/l10n_client.php | 10 +++++----- modules/gallery/controllers/welcome_message.php | 2 +- modules/notification/controllers/notification.php | 2 +- modules/user/controllers/login.php | 2 +- modules/user/controllers/logout.php | 2 +- modules/user/controllers/password.php | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) (limited to 'modules') diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 8455d95c..183c26d0 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -42,9 +42,9 @@ class Albums_Controller extends Items_Controller { $index = $album->get_position($show); $page = ceil($index / $page_size); if ($page == 1) { - url::redirect($album->url()); + url::redirect($album->abs_url()); } else { - url::redirect($album->url("page=$page")); + url::redirect($album->abs_url("page=$page")); } } @@ -55,9 +55,9 @@ class Albums_Controller extends Items_Controller { // Make sure that the page references a valid offset if ($page < 1) { - url::redirect($album->url()); + url::redirect($album->abs_url()); } else if ($page > $max_pages) { - url::redirect($album->url("page=$max_pages")); + url::redirect($album->abs_url("page=$max_pages")); } $template = new Theme_View("page.html", "album"); diff --git a/modules/gallery/controllers/items.php b/modules/gallery/controllers/items.php index 13891726..7f60f2b7 100644 --- a/modules/gallery/controllers/items.php +++ b/modules/gallery/controllers/items.php @@ -25,6 +25,6 @@ class Items_Controller extends REST_Controller { // differently. We could also just delegate here, but it feels more appropriate // to have a single canonical resource mapping. access::required("view", $item); - return url::redirect($item->url(array(), true)); + return url::redirect($item->abs_url()); } } diff --git a/modules/gallery/controllers/l10n_client.php b/modules/gallery/controllers/l10n_client.php index 16d39024..6e19310b 100644 --- a/modules/gallery/controllers/l10n_client.php +++ b/modules/gallery/controllers/l10n_client.php @@ -90,14 +90,14 @@ class L10n_Client_Controller extends Controller { } $session = Session::instance(); - $l10n_mode = $session->get("l10n_mode", false); + $l10n_mode = $session->get("l10n_mode", false); $session->set("l10n_mode", !$l10n_mode); $redirect_url = "admin/languages"; - if (!$l10n_mode) { - $redirect_url .= "#l10n-client"; - } - + if (!$l10n_mode) { + $redirect_url .= "#l10n-client"; + } + url::redirect($redirect_url); } diff --git a/modules/gallery/controllers/welcome_message.php b/modules/gallery/controllers/welcome_message.php index a4b690e3..8fd1e0a0 100644 --- a/modules/gallery/controllers/welcome_message.php +++ b/modules/gallery/controllers/welcome_message.php @@ -20,7 +20,7 @@ class Welcome_Message_Controller extends Controller { public function index() { if (!user::active()->admin) { - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } $v = new View("welcome_message.html"); diff --git a/modules/notification/controllers/notification.php b/modules/notification/controllers/notification.php index 5745de5d..d502b9fe 100644 --- a/modules/notification/controllers/notification.php +++ b/modules/notification/controllers/notification.php @@ -31,6 +31,6 @@ class Notification_Controller extends Controller { notification::add_watch($item); message::success(sprintf(t("You are now watching %s"), html::purify($item->title))); } - url::redirect($item->url(array(), true)); + url::redirect($item->abs_url()); } } diff --git a/modules/user/controllers/login.php b/modules/user/controllers/login.php index dcac0723..8bee7db5 100644 --- a/modules/user/controllers/login.php +++ b/modules/user/controllers/login.php @@ -48,7 +48,7 @@ class Login_Controller extends Controller { list ($valid, $form) = $this->_auth("login/auth_html"); if ($valid) { - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } else { print $form; } diff --git a/modules/user/controllers/logout.php b/modules/user/controllers/logout.php index 3bf274a6..45d397ad 100644 --- a/modules/user/controllers/logout.php +++ b/modules/user/controllers/logout.php @@ -31,7 +31,7 @@ class Logout_Controller extends Controller { // Don't use url::redirect() because it'll call url::site() and munge the continue url. header("Location: $continue_url"); } else { - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } } } diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index 8c18916e..92608dcd 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -130,7 +130,7 @@ class Password_Controller extends Controller { $user->hash = null; $user->save(); message::success(t("Password reset successfully")); - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } else { print $view; } -- cgit v1.2.3 From 882a6d9a5dbf04ac26e046713f47068cd1361b74 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:33:04 -0700 Subject: Convert a couple of instances of Item_Model::url(array(), true) to Item_Model::abs_url() --- modules/notification/views/item_added.html.php | 4 ++-- modules/notification/views/item_updated.html.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'modules') diff --git a/modules/notification/views/item_added.html.php b/modules/notification/views/item_added.html.php index f697fea6..1ea3720d 100644 --- a/modules/notification/views/item_added.html.php +++ b/modules/notification/views/item_added.html.php @@ -13,8 +13,8 @@
      diff --git a/modules/notification/views/item_updated.html.php b/modules/notification/views/item_updated.html.php index ba03540a..9c200964 100644 --- a/modules/notification/views/item_updated.html.php +++ b/modules/notification/views/item_updated.html.php @@ -17,7 +17,7 @@ - + original("description") != $item->description): ?> -- cgit v1.2.3 From af4411a44750b373916b841e01dac8ab434be68c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:55:36 -0700 Subject: Put the buttons for album/photo dialogs in their own group in the form so that they appear at the end, after any other groups that other modules add. Thanks Glooper! --- modules/gallery/helpers/album.php | 1 + modules/gallery/helpers/photo.php | 1 + 2 files changed, 2 insertions(+) (limited to 'modules') diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index bae480b7..dfb1e66d 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -152,6 +152,7 @@ class album_Core { module::event("item_edit_form", $parent, $form); + $group = $form->group("buttons")->label(""); $group->hidden("type")->value("album"); $group->submit("")->value(t("Modify")); $form->add_rules_from(ORM::factory("item")); diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index a56c7e3c..3d9fbe69 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -178,6 +178,7 @@ class photo_Core { module::event("item_edit_form", $photo, $form); + $group = $form->group("buttons")->label(""); $group->submit("")->value(t("Modify")); $form->add_rules_from(ORM::factory("item")); return $form; -- cgit v1.2.3 From 7ec490b6009965920fea35e971b29f11df6e6bff Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 11 Sep 2009 11:04:35 -0700 Subject: rawurlencode() path components in relative_path_cache and relative_url_cache so that they're safe for browser use. --- modules/gallery/models/item.php | 4 ++-- modules/gallery/tests/Item_Model_Test.php | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'modules') diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index da1f6959..a87997c6 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -284,8 +284,8 @@ class Item_Model extends ORM_MPTT { ->where("id <>", 1) ->orderby("left_ptr", "ASC") ->get() as $row) { - $names[] = urlencode($row->name); - $slugs[] = urlencode($row->slug); + $names[] = rawurlencode($row->name); + $slugs[] = rawurlencode($row->slug); } $this->relative_path_cache = implode($names, "/"); $this->relative_url_cache = implode($slugs, "/"); 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()); + } } -- cgit v1.2.3 From 1d40c77c4c05a85fbf6bbb96820fb98cbaa989eb Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 12 Sep 2009 08:53:24 -0700 Subject: Update the organize module to use the release version of jquery Selectable. Unfortunately this does not have the functionality to select additional thumbnails using the ctrl or alt-keys, it is preferable to forking the Selectable component. This functionality should arrive with ui.jquery 1.8.x --- modules/organize/css/organize.css | 5 +++-- modules/organize/js/organize.js | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'modules') diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 15b5538d..b1cef33c 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -102,12 +102,13 @@ width: 9em; } -.gOrganizeMicroThumbGridCell.ui-state-selected { +.gOrganizeMicroThumbGridCell.ui-selecting, +.gOrganizeMicroThumbGridCell.ui-selected { margin: 2px; border: 2px solid #13A; } -.ui-selectable-lasso { +.ui-selectable-helper { z-index: 2000 !important; border: 1px dashed #00F; opacity: 0.25; diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index c30f89e0..7d204708 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,12 +1,12 @@ (function($) { $.organize = { micro_thumb_draggable: { - handle: ".ui-state-selected", + handle: ".ui-selected", distance: 10, cursorAt: { left: -10, top: -10}, appendTo: "#gOrganizeMicroThumbPanel", helper: function(event, ui) { - var selected = $(".ui-draggable.ui-state-selected img"); + var selected = $(".ui-draggable.ui-selected img"); if (selected.length) { var set = $('
      ') .css({ @@ -37,7 +37,7 @@ }, start: function(event, ui) { - $("#gOrganizeMicroThumbPanel .ui-state-selected").hide(); + $("#gOrganizeMicroThumbPanel .ui-selected").hide(); }, drag: function(event, ui) { @@ -80,7 +80,7 @@ greedy: true, drop: function(event, ui) { if ($(event.target).hasClass("gViewOnly")) { - $(".ui-state-selected").show(); + $(".ui-selected").show(); $(".gOrganizeMicroThumbGridCell").css("borderStyle", "none"); } else { $.organize.do_drop({ -- cgit v1.2.3 From 0bb489b69438266359bfd22955f4d5c8f9d6ade3 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 12 Sep 2009 10:02:27 -0700 Subject: Properly internationalize the text for the By: line. This gets rid of the escaping problem. --- modules/info/helpers/info_theme.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/info/helpers/info_theme.php b/modules/info/helpers/info_theme.php index 51378e54..e5f9c909 100644 --- a/modules/info/helpers/info_theme.php +++ b/modules/info/helpers/info_theme.php @@ -38,7 +38,9 @@ class info_theme_Core { if ($item->owner) { $results .= "
    • "; if ($item->owner->url) { - $results .= t("By: %owner_name", array("owner_name" => "owner->url}\">{$item->owner->full_name}")); + $results .= t("By: %owner_name", + array("owner_name" => $item->owner->display_name(), + "owner_url" => $item->owner->url)); } else { $results .= t("By: %owner_name", array("owner_name" => "{$item->owner->full_name}")); } -- cgit v1.2.3 From 961bc3b18571b5f3ad2a355b71d40c4830dd44ba Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 12 Sep 2009 10:06:24 -0700 Subject: Use user::display_name() in another case where it was missing. --- modules/info/helpers/info_theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules') diff --git a/modules/info/helpers/info_theme.php b/modules/info/helpers/info_theme.php index e5f9c909..4bf894ad 100644 --- a/modules/info/helpers/info_theme.php +++ b/modules/info/helpers/info_theme.php @@ -42,7 +42,7 @@ class info_theme_Core { array("owner_name" => $item->owner->display_name(), "owner_url" => $item->owner->url)); } else { - $results .= t("By: %owner_name", array("owner_name" => "{$item->owner->full_name}")); + $results .= t("By: %owner_name", array("owner_name" => $item->owner->display_name())); } $results .= "
    • "; } -- cgit v1.2.3 From 823fa2fc8339a6638ef4f0fcdae7f96e99a4f0bd Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 12 Sep 2009 10:33:46 -0700 Subject: Updated for url format changes applied in 2aad580f53dbc06bb170c710467b47a5a532c6c8. --- modules/gallery/tests/xss_data.txt | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'modules') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 8c71740e..193d2ca1 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 @@ -325,6 +328,8 @@ 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 84 DIRTY_JS item::root()->url() +themes/default/views/page.html.php 98 DIRTY_JS $parent->url("show={$theme->item()->id}") 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 -- cgit v1.2.3 From caa2002d7777e0ceb884d4c628650804620ca2b6 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 13 Sep 2009 01:04:16 -0700 Subject: If there's a show= param and we can't find the given id in the current album, just ignore the parameter. --- modules/gallery/controllers/albums.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'modules') diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 183c26d0..08a60132 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -40,11 +40,13 @@ class Albums_Controller extends Items_Controller { if ($show) { $index = $album->get_position($show); - $page = ceil($index / $page_size); - if ($page == 1) { - url::redirect($album->abs_url()); - } else { - url::redirect($album->abs_url("page=$page")); + if ($index) { + $page = ceil($index / $page_size); + if ($page == 1) { + url::redirect($album->abs_url()); + } else { + url::redirect($album->abs_url("page=$page")); + } } } -- cgit v1.2.3
      @@ -21,7 +21,7 @@
      name ?>
      "> updated) ?>
      "> updated) ?>
      - - url(array(), true) ?> + + abs_url() ?>
      url(array(), true) ?>abs_url() ?>