summaryrefslogtreecommitdiff
path: root/modules/gallery
diff options
context:
space:
mode:
authorNathan Kinkade <nath@nkinka.de>2013-03-19 16:41:42 +0000
committerNathan Kinkade <nath@nkinka.de>2013-03-19 16:41:42 +0000
commit3908e37d965fa76ea774e76ddf42365a872a5f27 (patch)
tree457e1a1e465f83855eee96ba287cd91f1623395c /modules/gallery
parent711651f727e093cc7357a6bbff6bd992fd6dfd80 (diff)
parent1eab94f6062b5f54ea5d9db01d968e7195f3de9d (diff)
Merge branch 'master' of git://github.com/gallery/gallery3
Diffstat (limited to 'modules/gallery')
-rw-r--r--modules/gallery/controllers/admin.php2
-rw-r--r--modules/gallery/controllers/admin_dashboard.php1
-rw-r--r--modules/gallery/controllers/admin_maintenance.php1
-rw-r--r--modules/gallery/controllers/admin_modules.php1
-rw-r--r--modules/gallery/controllers/admin_movies.php72
-rw-r--r--modules/gallery/controllers/admin_theme_options.php2
-rw-r--r--modules/gallery/controllers/file_proxy.php21
-rw-r--r--modules/gallery/controllers/quick.php1
-rw-r--r--modules/gallery/controllers/upgrader.php1
-rw-r--r--modules/gallery/controllers/uploader.php156
-rw-r--r--modules/gallery/css/gallery.css19
-rw-r--r--modules/gallery/helpers/album.php9
-rw-r--r--modules/gallery/helpers/block_manager.php10
-rw-r--r--modules/gallery/helpers/gallery_event.php39
-rw-r--r--modules/gallery/helpers/gallery_installer.php32
-rw-r--r--modules/gallery/helpers/gallery_task.php6
-rw-r--r--modules/gallery/helpers/gallery_theme.php4
-rw-r--r--modules/gallery/helpers/graphics.php6
-rw-r--r--modules/gallery/helpers/item.php81
-rw-r--r--modules/gallery/helpers/legal_file.php32
-rw-r--r--modules/gallery/helpers/module.php72
-rw-r--r--modules/gallery/helpers/movie.php36
-rw-r--r--modules/gallery/helpers/photo.php7
-rw-r--r--modules/gallery/helpers/system.php33
-rw-r--r--modules/gallery/helpers/task.php2
-rw-r--r--modules/gallery/images/ffmpeg.pngbin0 -> 2888 bytes
-rw-r--r--modules/gallery/images/loading-small.gifbin0 -> 673 bytes
-rw-r--r--modules/gallery/js/albums_form_add.js29
-rw-r--r--modules/gallery/js/l10n_client.js14
-rw-r--r--modules/gallery/libraries/Admin_View.php36
-rw-r--r--modules/gallery/libraries/Gallery_View.php130
-rw-r--r--modules/gallery/libraries/IdentityProvider.php3
-rw-r--r--modules/gallery/libraries/SafeString.php2
-rw-r--r--modules/gallery/libraries/Theme_View.php30
-rw-r--r--modules/gallery/models/item.php139
-rw-r--r--modules/gallery/module.info2
-rw-r--r--modules/gallery/tests/File_Proxy_Controller_Test.php2
-rw-r--r--modules/gallery/tests/Html_Helper_Test.php2
-rw-r--r--modules/gallery/tests/Item_Helper_Test.php159
-rw-r--r--modules/gallery/tests/Item_Model_Test.php119
-rw-r--r--modules/gallery/tests/Legal_File_Helper_Test.php32
-rw-r--r--modules/gallery/tests/Movie_Helper_Test.php3
-rw-r--r--modules/gallery/tests/Photo_Helper_Test.php3
-rw-r--r--modules/gallery/tests/SafeString_Test.php4
-rw-r--r--modules/gallery/tests/controller_auth_data.txt1
-rw-r--r--modules/gallery/tests/xss_data.txt133
-rw-r--r--modules/gallery/views/admin_advanced_settings.html.php4
-rw-r--r--modules/gallery/views/admin_dashboard.html.php7
-rw-r--r--modules/gallery/views/admin_modules.html.php6
-rw-r--r--modules/gallery/views/admin_movies.html.php44
-rw-r--r--modules/gallery/views/form_uploadify.html.php2
-rw-r--r--modules/gallery/views/in_place_edit.html.php2
-rw-r--r--modules/gallery/views/menu_ajax_link.html.php2
-rw-r--r--modules/gallery/views/movieplayer.html.php58
-rw-r--r--modules/gallery/views/upgrader.html.php11
55 files changed, 1212 insertions, 413 deletions
diff --git a/modules/gallery/controllers/admin.php b/modules/gallery/controllers/admin.php
index c9d944cc..b35a9299 100644
--- a/modules/gallery/controllers/admin.php
+++ b/modules/gallery/controllers/admin.php
@@ -55,7 +55,7 @@ class Admin_Controller extends Controller {
$method = "index";
}
- if (!method_exists($controller_name, $method)) {
+ if (!class_exists($controller_name) || !method_exists($controller_name, $method)) {
throw new Kohana_404_Exception();
}
diff --git a/modules/gallery/controllers/admin_dashboard.php b/modules/gallery/controllers/admin_dashboard.php
index 6bd36b07..53172109 100644
--- a/modules/gallery/controllers/admin_dashboard.php
+++ b/modules/gallery/controllers/admin_dashboard.php
@@ -26,6 +26,7 @@ class Admin_Dashboard_Controller extends Admin_Controller {
$view->sidebar = "<div id=\"g-admin-dashboard-sidebar\">" .
block_manager::get_html("dashboard_sidebar") .
"</div>";
+ $view->content->obsolete_modules_message = module::get_obsolete_modules_message();
print $view;
}
diff --git a/modules/gallery/controllers/admin_maintenance.php b/modules/gallery/controllers/admin_maintenance.php
index 23df33ee..32f20784 100644
--- a/modules/gallery/controllers/admin_maintenance.php
+++ b/modules/gallery/controllers/admin_maintenance.php
@@ -55,6 +55,7 @@ class Admin_Maintenance_Controller extends Admin_Controller {
->where("expiration", "<>", 0)
->where("expiration", "<=", time())
->execute();
+ module::deactivate_missing_modules();
}
/**
diff --git a/modules/gallery/controllers/admin_modules.php b/modules/gallery/controllers/admin_modules.php
index d13ec1c6..177a925d 100644
--- a/modules/gallery/controllers/admin_modules.php
+++ b/modules/gallery/controllers/admin_modules.php
@@ -26,6 +26,7 @@ class Admin_Modules_Controller extends Admin_Controller {
$view->page_title = t("Modules");
$view->content = new View("admin_modules.html");
$view->content->available = module::available();
+ $view->content->obsolete_modules_message = module::get_obsolete_modules_message();
print $view;
}
diff --git a/modules/gallery/controllers/admin_movies.php b/modules/gallery/controllers/admin_movies.php
new file mode 100644
index 00000000..38fa44a5
--- /dev/null
+++ b/modules/gallery/controllers/admin_movies.php
@@ -0,0 +1,72 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2013 Bharat Mediratta
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+class Admin_Movies_Controller extends Admin_Controller {
+ public function index() {
+ // Print screen from new form.
+ $form = $this->_get_admin_form();
+ $this->_print_view($form);
+ }
+
+ public function save() {
+ access::verify_csrf();
+ $form = $this->_get_admin_form();
+ if ($form->validate()) {
+ module::set_var("gallery", "movie_allow_uploads", $form->settings->allow_uploads->value);
+ if ($form->settings->rebuild_thumbs->value) {
+ graphics::mark_dirty(true, false, "movie");
+ }
+ // All done - redirect with message.
+ message::success(t("Movies settings updated successfully"));
+ url::redirect("admin/movies");
+ }
+ // Something went wrong - print view from existing form.
+ $this->_print_view($form);
+ }
+
+ private function _print_view($form) {
+ list ($ffmpeg_version, $ffmpeg_date) = movie::get_ffmpeg_version();
+ $ffmpeg_version = $ffmpeg_date ? "{$ffmpeg_version} ({$ffmpeg_date})" : $ffmpeg_version;
+ $ffmpeg_path = movie::find_ffmpeg();
+ $ffmpeg_dir = substr($ffmpeg_path, 0, strrpos($ffmpeg_path, "/"));
+
+ $view = new Admin_View("admin.html");
+ $view->page_title = t("Movies settings");
+ $view->content = new View("admin_movies.html");
+ $view->content->form = $form;
+ $view->content->ffmpeg_dir = $ffmpeg_dir;
+ $view->content->ffmpeg_version = $ffmpeg_version;
+ print $view;
+ }
+
+ private function _get_admin_form() {
+ $form = new Forge("admin/movies/save", "", "post", array("id" => "g-movies-admin-form"));
+ $group = $form->group("settings")->label(t("Settings"));
+ $group->dropdown("allow_uploads")
+ ->label(t("Allow movie uploads into Gallery (does not affect existing movies)"))
+ ->options(array("autodetect"=>t("only if FFmpeg is detected (default)"),
+ "always"=>t("always"), "never"=>t("never")))
+ ->selected(module::get_var("gallery", "movie_allow_uploads", "autodetect"));
+ $group->checkbox("rebuild_thumbs")
+ ->label(t("Rebuild all movie thumbnails (once FFmpeg is installed, use this to update existing movie thumbnails)"))
+ ->checked(false); // always set as false
+ $form->submit("save")->value(t("Save"));
+ return $form;
+ }
+}
diff --git a/modules/gallery/controllers/admin_theme_options.php b/modules/gallery/controllers/admin_theme_options.php
index aead8bae..38d2b0a8 100644
--- a/modules/gallery/controllers/admin_theme_options.php
+++ b/modules/gallery/controllers/admin_theme_options.php
@@ -34,7 +34,6 @@ class Admin_Theme_Options_Controller extends Admin_Controller {
module::set_var("gallery", "page_size", $form->edit_theme->page_size->value);
$thumb_size = $form->edit_theme->thumb_size->value;
- $thumb_dirty = false;
if (module::get_var("gallery", "thumb_size") != $thumb_size) {
graphics::remove_rule("gallery", "thumb", "gallery_graphics::resize");
graphics::add_rule(
@@ -45,7 +44,6 @@ class Admin_Theme_Options_Controller extends Admin_Controller {
}
$resize_size = $form->edit_theme->resize_size->value;
- $resize_dirty = false;
if (module::get_var("gallery", "resize_size") != $resize_size) {
graphics::remove_rule("gallery", "resize", "gallery_graphics::resize");
graphics::add_rule(
diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php
index 7e5d0038..50f1aa26 100644
--- a/modules/gallery/controllers/file_proxy.php
+++ b/modules/gallery/controllers/file_proxy.php
@@ -66,24 +66,8 @@ class File_Proxy_Controller extends Controller {
throw $e;
}
- // If the last element is .album.jpg, pop that off since it's not a real item
- $path = preg_replace("|/.album.jpg$|", "", $path);
-
- $item = item::find_by_path($path);
- if (!$item->loaded()) {
- // We didn't turn it up. If we're looking for a .jpg then it's it's possible that we're
- // requesting the thumbnail for a movie. In that case, the movie file would
- // have been converted to a .jpg. So try some alternate types:
- if (preg_match('/.jpg$/', $path)) {
- foreach (legal_file::get_movie_extensions() as $ext) {
- $movie_path = preg_replace('/.jpg$/', ".$ext", $path);
- $item = item::find_by_path($movie_path);
- if ($item->loaded()) {
- break;
- }
- }
- }
- }
+ // Get the item model using the path and type (which corresponds to a var subdir)
+ $item = item::find_by_path($path, $type);
if (!$item->loaded()) {
$e = new Kohana_404_Exception();
@@ -162,7 +146,6 @@ class File_Proxy_Controller extends Controller {
// going to buffer up whatever file we're proxying (and it may be very large). This may
// affect embedding or systems with PHP's output_buffering enabled.
while (ob_get_level()) {
- Kohana_Log::add("error","".print_r(ob_get_level(),1));
if (!@ob_end_clean()) {
// ob_end_clean() can return false if the buffer can't be removed for some reason
// (zlib output compression buffers sometimes cause problems).
diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php
index 2ddf2a4b..4b21d9ee 100644
--- a/modules/gallery/controllers/quick.php
+++ b/modules/gallery/controllers/quick.php
@@ -41,7 +41,6 @@ class Quick_Controller extends Controller {
gallery_graphics::rotate($item->file_path(), $tmpfile, array("degrees" => $degrees), $item);
$item->set_data_file($tmpfile);
$item->save();
- unlink($tmpfile);
}
if (Input::instance()->get("page_type") == "collection") {
diff --git a/modules/gallery/controllers/upgrader.php b/modules/gallery/controllers/upgrader.php
index d3c6e2ec..6b3a9ef6 100644
--- a/modules/gallery/controllers/upgrader.php
+++ b/modules/gallery/controllers/upgrader.php
@@ -46,6 +46,7 @@ class Upgrader_Controller extends Controller {
$view->available = module::available();
$view->failed = $failed ? explode(",", $failed) : array();
$view->done = $available_upgrades == 0;
+ $view->obsolete_modules_message = module::get_obsolete_modules_message();
print $view;
}
diff --git a/modules/gallery/controllers/uploader.php b/modules/gallery/controllers/uploader.php
index 78437071..54e1476b 100644
--- a/modules/gallery/controllers/uploader.php
+++ b/modules/gallery/controllers/uploader.php
@@ -47,52 +47,25 @@ class Uploader_Controller extends Controller {
$form = $this->_get_add_form($album);
- // Uploadify adds its own field to the form, so validate that separately.
- $file_validation = new Validation($_FILES);
- $file_validation->add_rules(
- "Filedata", "upload::valid", "upload::required",
- "upload::type[" . implode(",", legal_file::get_extensions()) . "]");
-
- if ($form->validate() && $file_validation->validate()) {
- $temp_filename = upload::save("Filedata");
- Event::add("system.shutdown", create_function("", "unlink(\"$temp_filename\");"));
+ if ($form->validate()) {
+ // Uploadify puts the result in $_FILES["Filedata"] - process it.
try {
- $item = ORM::factory("item");
- $item->name = substr(basename($temp_filename), 10); // Skip unique identifier Kohana adds
- $item->title = item::convert_filename_to_title($item->name);
- $item->parent_id = $album->id;
- $item->set_data_file($temp_filename);
-
- $path_info = @pathinfo($temp_filename);
- if (array_key_exists("extension", $path_info) &&
- legal_file::get_movie_extensions($path_info["extension"])) {
- $item->type = "movie";
- $item->save();
- log::success("content", t("Added a movie"),
- html::anchor("movies/$item->id", t("view movie")));
- } else {
- $item->type = "photo";
- $item->save();
- log::success("content", t("Added a photo"),
- html::anchor("photos/$item->id", t("view photo")));
- }
+ list ($tmp_name, $name) = $this->_process_upload("Filedata");
+ } catch (Exception $e) {
+ header("HTTP/1.1 400 Bad Request");
+ print "ERROR: " . $e->getMessage();
+ return;
+ }
+ // We have a valid upload file (of unknown type) - build an item from it.
+ try {
+ $item = $this->_add_item($id, $tmp_name, $name);
module::event("add_photos_form_completed", $item, $form);
+ print "FILEID: $item->id";
} catch (Exception $e) {
- // The Flash uploader has no good way of reporting complex errors, so just keep it simple.
- Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString());
-
- // Ugh. I hate to use instanceof, But this beats catching the exception separately since
- // we mostly want to treat it the same way as all other exceptions
- if ($e instanceof ORM_Validation_Exception) {
- Kohana_Log::add("error", "Validation errors: " . print_r($e->validation->errors(), 1));
- }
-
header("HTTP/1.1 500 Internal Server Error");
print "ERROR: " . $e->getMessage();
- return;
}
- print "FILEID: $item->id";
} else {
header("HTTP/1.1 400 Bad Request");
print "ERROR: " . t("Invalid upload");
@@ -107,27 +80,122 @@ class Uploader_Controller extends Controller {
(int)$success_count,
array("error" => (int)$error_count));
} else {
- print t2("Uploaded %count photo", "Uploaded %count photos", $success_count);}
+ print t2("Uploaded %count photo", "Uploaded %count photos", $success_count);
+ }
}
public function finish() {
access::verify_csrf();
-
batch::stop();
json::reply(array("result" => "success"));
}
- private function _get_add_form($album) {
+ private function _get_add_form($album) {
$form = new Forge("uploader/finish", "", "post", array("id" => "g-add-photos-form"));
$group = $form->group("add_photos")
->label(t("Add photos to %album_title", array("album_title" => html::purify($album->title))));
$group->uploadify("uploadify")->album($album);
- $group = $form->group("actions");
- $group->uploadify_buttons("");
+ $group_actions = $form->group("actions");
+ $group_actions->uploadify_buttons("");
+ $inputs_before_event = array_keys($form->add_photos->inputs);
module::event("add_photos_form", $album, $form);
+ $inputs_after_event = array_keys($form->add_photos->inputs);
+
+ // For each new input in add_photos, attach JS to make uploadify update its value.
+ foreach (array_diff($inputs_after_event, $inputs_before_event) as $input) {
+ if (!$input) {
+ // Likely a script input - don't do anything with it.
+ continue;
+ }
+ $group->uploadify->script_data($input, $group->{$input}->value);
+ $group->script("")
+ ->text("$('input[name=\"$input\"]').change(function (event) {
+ $('#g-uploadify').uploadifySettings('scriptData', {'$input': $(this).val()});
+ });");
+ }
return $form;
}
+
+ /**
+ * Process the uploaded file. This handles the interface with Kohana's upload and validation
+ * code, and marks the new temp file for deletion on shutdown. It returns the temp file path
+ * (tmp_name) and filename (name), analogous to their respective $_FILES elements.
+ * If the upload is invalid, it will throw an exception. Note that no type-checking (e.g. jpg,
+ * mp4,...) is performed here.
+ * @TODO: consider moving this to a common controller which is extended by various uploaders.
+ *
+ * @param string name of $_FILES input
+ * @return array array($tmp_name, $name)
+ */
+ private function _process_upload($file) {
+ // Validate file data. At this point, any file extension is still valid.
+ $file_validation = new Validation($_FILES);
+ $file_validation->add_rules($file, "upload::valid", "upload::required");
+ if (!$file_validation->validate()) {
+ throw new Exception(t("Invalid upload"));
+ }
+
+ // Save temp file and mark for deletion when done.
+ $tmp_name = upload::save($file);
+ system::delete_later($tmp_name);
+
+ // Get uploaded filename. This is different than tmp_name since it hasn't been uniquified.
+ $name = $_FILES[$file]["name"];
+
+ return array($tmp_name, $name);
+ }
+
+ /**
+ * Add photo or movie from upload. Once we have a valid file, this generates an item model
+ * from it. It returns the item model on success, and throws an exception and adds log entries
+ * on failure.
+ * @TODO: consider moving this to a common controller which is extended by various uploaders.
+ *
+ * @param int parent album id
+ * @param string temp file path (analogous to $_FILES[...]["tmp_name"])
+ * @param string filename (analogous to $_FILES[...]["name"])
+ * @return object new item model
+ */
+ private function _add_item($album_id, $tmp_name, $name) {
+ $extension = pathinfo($name, PATHINFO_EXTENSION);
+
+ try {
+ $item = ORM::factory("item");
+ $item->name = $name;
+ $item->title = item::convert_filename_to_title($name);
+ $item->parent_id = $album_id;
+ $item->set_data_file($tmp_name);
+
+ if (!$extension) {
+ throw new Exception(t("Uploaded file has no extension"));
+ } else if (legal_file::get_photo_extensions($extension)) {
+ $item->type = "photo";
+ $item->save();
+ log::success("content", t("Added a photo"),
+ html::anchor("photos/$item->id", t("view photo")));
+ } else if (movie::allow_uploads() && legal_file::get_movie_extensions($extension)) {
+ $item->type = "movie";
+ $item->save();
+ log::success("content", t("Added a movie"),
+ html::anchor("movies/$item->id", t("view movie")));
+ } else {
+ throw new Exception(t("Uploaded file has illegal extension"));
+ }
+ } catch (Exception $e) {
+ // Log errors then re-throw exception.
+ Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString());
+
+ // If we have a validation error, add an additional log entry.
+ if ($e instanceof ORM_Validation_Exception) {
+ Kohana_Log::add("error", "Validation errors: " . print_r($e->validation->errors(), 1));
+ }
+
+ throw $e;
+ }
+
+ return $item;
+ }
}
diff --git a/modules/gallery/css/gallery.css b/modules/gallery/css/gallery.css
index 7e711156..323c2e83 100644
--- a/modules/gallery/css/gallery.css
+++ b/modules/gallery/css/gallery.css
@@ -149,6 +149,25 @@
text-align: center;
}
+/* Dialogs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/**
+ * Newer Themeroller-based themes do this on their own, but older
+ * themes need help ensuring that dialogs and overlays are on top
+ */
+.ui-front {
+ z-index: 1000
+}
+
+/* Autocomplete ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+.ui-autocomplete {
+ text-align: left;
+}
+
+.ui-autocomplete-loading {
+ background: #e8e8e8 url('../images/loading-small.gif') no-repeat center center;
+}
+
/** *******************************************************************
* 2) Admin
**********************************************************************/
diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php
index 23aed8ac..fe6b03fc 100644
--- a/modules/gallery/helpers/album.php
+++ b/modules/gallery/helpers/album.php
@@ -34,12 +34,16 @@ class album_Core {
->error_messages("length", t("Your title is too long"));
$group->textarea("description")->label(t("Description"));
$group->input("name")->label(t("Directory name"))
- ->error_messages("no_slashes", t("The directory name can't contain the \"/\" character"))
+ ->error_messages("no_slashes", t("The directory name can't contain a \"/\""))
+ ->error_messages("no_backslashes", t("The directory name can't contain a \"\\\""))
+ ->error_messages("no_trailing_period", t("The directory name can't end in \".\""))
->error_messages("required", t("You must provide a directory name"))
->error_messages("length", t("Your directory name is too long"))
->error_messages("conflict", t("There is already a movie, photo or album with this name"));
$group->input("slug")->label(t("Internet Address"))
->error_messages(
+ "conflict", t("There is already a movie, photo or album with this internet address"))
+ ->error_messages(
"reserved", t("This address is reserved and can't be used."))
->error_messages(
"not_url_safe",
@@ -64,13 +68,14 @@ class album_Core {
$group = $form->group("edit_item")->label(t("Edit Album"));
$group->input("title")->label(t("Title"))->value($parent->title)
- ->error_messages("required", t("You must provide a title"))
+ ->error_messages("required", t("You must provide a title"))
->error_messages("length", t("Your title is too long"));
$group->textarea("description")->label(t("Description"))->value($parent->description);
if ($parent->id != 1) {
$group->input("name")->label(t("Directory Name"))->value($parent->name)
->error_messages("conflict", t("There is already a movie, photo or album with this name"))
->error_messages("no_slashes", t("The directory name can't contain a \"/\""))
+ ->error_messages("no_backslashes", t("The directory name can't contain a \"\\\""))
->error_messages("no_trailing_period", t("The directory name can't end in \".\""))
->error_messages("required", t("You must provide a directory name"))
->error_messages("length", t("Your directory name is too long"));
diff --git a/modules/gallery/helpers/block_manager.php b/modules/gallery/helpers/block_manager.php
index bd6ca1c8..a2279468 100644
--- a/modules/gallery/helpers/block_manager.php
+++ b/modules/gallery/helpers/block_manager.php
@@ -35,7 +35,7 @@ class block_manager_Core {
static function activate_blocks($module_name) {
$block_class = "{$module_name}_block";
- if (method_exists($block_class, "get_site_list")) {
+ if (class_exists($block_class) && method_exists($block_class, "get_site_list")) {
$blocks = call_user_func(array($block_class, "get_site_list"));
foreach (array_keys($blocks) as $block_id) {
block_manager::add("site_sidebar", $module_name, $block_id);
@@ -61,14 +61,14 @@ class block_manager_Core {
static function deactivate_blocks($module_name) {
$block_class = "{$module_name}_block";
- if (method_exists($block_class, "get_site_list")) {
+ if (class_exists($block_class) && method_exists($block_class, "get_site_list")) {
$blocks = call_user_func(array($block_class, "get_site_list"));
foreach (array_keys($blocks) as $block_id) {
block_manager::remove_blocks_for_module("site_sidebar", $module_name);
}
}
- if (method_exists($block_class, "get_admin_list")) {
+ if (class_exists($block_class) && method_exists($block_class, "get_admin_list")) {
$blocks = call_user_func(array($block_class, "get_admin_list"));
foreach (array("dashboard_sidebar", "dashboard_center") as $location) {
block_manager::remove_blocks_for_module($location, $module_name);
@@ -89,7 +89,7 @@ class block_manager_Core {
foreach (module::active() as $module) {
$class_name = "{$module->name}_block";
- if (method_exists($class_name, $function)) {
+ if (class_exists($class_name) && method_exists($class_name, $function)) {
foreach (call_user_func(array($class_name, $function)) as $id => $title) {
$blocks["{$module->name}:$id"] = $title;
}
@@ -102,7 +102,7 @@ class block_manager_Core {
$active = block_manager::get_active($location);
$result = "";
foreach ($active as $id => $desc) {
- if (method_exists("$desc[0]_block", "get")) {
+ if (class_exists("$desc[0]_block") && method_exists("$desc[0]_block", "get")) {
$block = call_user_func(array("$desc[0]_block", "get"), $desc[1], $theme);
if (!empty($block)) {
$block->id = $id;
diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php
index aeb1c7eb..a319b9c6 100644
--- a/modules/gallery/helpers/gallery_event.php
+++ b/modules/gallery/helpers/gallery_event.php
@@ -36,6 +36,41 @@ class gallery_event_Core {
locales::set_request_locale();
}
+ static function gallery_shutdown() {
+ // Every 500th request, do a pass over var/logs and var/tmp and delete old files.
+ // Limit ourselves to deleting a single file so that we don't spend too much CPU
+ // time on it. As long as servers call this at least twice a day they'll eventually
+ // wind up with a clean var/logs directory because we only create 1 file a day there.
+ // var/tmp might be stickier because theoretically we could wind up spamming that
+ // dir with a lot of files. But let's start with this and refine as we go.
+ if (!(rand() % 500)) {
+ // Note that this code is roughly duplicated in gallery_task::file_cleanup
+ $threshold = time() - 1209600; // older than 2 weeks
+ foreach(array("logs", "tmp") as $dir) {
+ $dir = VARPATH . $dir;
+ if ($dh = opendir($dir)) {
+ while (($file = readdir($dh)) !== false) {
+ if ($file[0] == ".") {
+ continue;
+ }
+
+ // Ignore directories for now, but we should really address them in the long term.
+ if (is_dir("$dir/$file")) {
+ continue;
+ }
+
+ if (filemtime("$dir/$file") <= $threshold) {
+ unlink("$dir/$file");
+ break;
+ }
+ }
+ }
+ }
+ }
+ // Delete all files marked using system::delete_later.
+ system::delete_marked_files();
+ }
+
static function user_deleted($user) {
$admin = identity::admin_user();
if (!empty($admin)) { // could be empty if there is not identity provider
@@ -399,6 +434,10 @@ class gallery_event_Core {
->label(t("Graphics"))
->url(url::site("admin/graphics")))
->append(Menu::factory("link")
+ ->id("movies_settings")
+ ->label(t("Movies"))
+ ->url(url::site("admin/movies")))
+ ->append(Menu::factory("link")
->id("languages")
->label(t("Languages"))
->url(url::site("admin/languages")))
diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php
index 051a66cf..f1604150 100644
--- a/modules/gallery/helpers/gallery_installer.php
+++ b/modules/gallery/helpers/gallery_installer.php
@@ -797,6 +797,38 @@ class gallery_installer {
module::set_var("gallery", "movie_allow_uploads", "autodetect");
module::set_version("gallery", $version = 56);
}
+
+ if ($version == 56) {
+ // Cleanup possible instances where resize_dirty of albums or movies was set to 0. This is
+ // unlikely to have occurred, and doesn't currently matter much since albums and movies don't
+ // have resize images anyway. However, it may be useful to be consistent here going forward.
+ db::build()
+ ->update("items")
+ ->set("resize_dirty", 1)
+ ->where("type", "<>", "photo")
+ ->execute();
+ module::set_version("gallery", $version = 57);
+ }
+
+ if ($version == 57) {
+ // In v58 we changed the Item_Model validation code to disallow files or directories with
+ // backslashes in them, and we need to fix any existing items that have them. This is
+ // pretty unlikely, as having backslashes would have probably already caused other issues for
+ // users, but we should check anyway. This might be slow, but if it times out it can just
+ // pick up where it left off.
+ foreach (db::build()
+ ->from("items")
+ ->select("id")
+ ->where(db::expr("`name` REGEXP '\\\\\\\\'"), "=", 1) // one \, 3x escaped
+ ->order_by("id", "asc")
+ ->execute() as $row) {
+ set_time_limit(30);
+ $item = ORM::factory("item", $row->id);
+ $item->name = str_replace("\\", "_", $item->name);
+ $item->save();
+ }
+ module::set_version("gallery", $version = 58);
+ }
}
static function uninstall() {
diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php
index 856d2639..a79cb2d5 100644
--- a/modules/gallery/helpers/gallery_task.php
+++ b/modules/gallery/helpers/gallery_task.php
@@ -281,6 +281,7 @@ class gallery_task_Core {
switch ($task->get("mode", "init")) {
case "init":
$threshold = time() - 1209600; // older than 2 weeks
+ // Note that this code is roughly duplicated in gallery_event::gallery_shutdown
foreach(array("logs", "tmp") as $dir) {
$dir = VARPATH . $dir;
if ($dh = opendir($dir)) {
@@ -289,6 +290,11 @@ class gallery_task_Core {
continue;
}
+ // Ignore directories for now, but we should really address them in the long term.
+ if (is_dir("$dir/$file")) {
+ continue;
+ }
+
if (filemtime("$dir/$file") <= $threshold) {
$files[] = "$dir/$file";
}
diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php
index 3c6d71e9..e5f6b0b4 100644
--- a/modules/gallery/helpers/gallery_theme.php
+++ b/modules/gallery/helpers/gallery_theme.php
@@ -49,6 +49,10 @@ class gallery_theme_Core {
. $theme->script("l10n_client.js");
}
+ // Add MediaElementJS library
+ $buf .= $theme->script("mediaelementjs/mediaelement.js");
+ $buf .= $theme->script("mediaelementjs/mediaelementplayer.js");
+ $buf .= $theme->css("mediaelementjs/mediaelementplayer.css");
$buf .= $theme->css("uploadify/uploadify.css");
return $buf;
}
diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php
index e66908c4..459784c9 100644
--- a/modules/gallery/helpers/graphics.php
+++ b/modules/gallery/helpers/graphics.php
@@ -121,12 +121,6 @@ class graphics_Core {
if ($item->resize_dirty && $item->is_photo()) {
$ops["resize"] = $item->resize_path();
}
- if (empty($ops)) {
- $item->thumb_dirty = 0;
- $item->resize_dirty = 0;
- $item->save();
- return;
- }
try {
foreach ($ops as $target => $output_file) {
diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php
index 9882a9c5..bbbc81d6 100644
--- a/modules/gallery/helpers/item.php
+++ b/modules/gallery/helpers/item.php
@@ -203,10 +203,18 @@ class item_Core {
/**
* Find an item by its path. If there's no match, return an empty Item_Model.
* NOTE: the caller is responsible for performing security checks on the resulting item.
+ *
+ * In addition to $path, $var_subdir can be specified ("albums", "resizes", or "thumbs"). This
+ * corresponds to the file's directory in var, which is what's used in file_proxy. By specifying
+ * this, we can be smarter about items whose formats get converted (e.g. movies that get jpg
+ * thumbs). If omitted, it defaults to "albums" which looks for identical matches between $path
+ * and the item name, just like pre-v3.1 behavior.
+ *
* @param string $path
+ * @param string $var_subdir
* @return object Item_Model
*/
- static function find_by_path($path) {
+ static function find_by_path($path, $var_subdir="albums") {
$path = trim($path, "/");
// The root path name is NULL not "", hence this workaround.
@@ -214,35 +222,80 @@ class item_Core {
return item::root();
}
+ $search_full_name = true;
+ $album_thumb = false;
+ if (($var_subdir == "thumbs") && preg_match("|^(.*)/\.album\.jpg$|", $path, $matches)) {
+ // It's an album thumb - remove "/.album.jpg" from the path.
+ $path = $matches[1];
+ $album_thumb = true;
+ } else if (($var_subdir != "albums") && preg_match("/^(.*)\.jpg$/", $path, $matches)) {
+ // Item itself could be non-jpg (e.g. movies) - remove .jpg from path, don't search full name.
+ $path = $matches[1];
+ $search_full_name = false;
+ }
+
// Check to see if there's an item in the database with a matching relative_path_cache value.
- // Since that field is urlencoded, we must urlencoded the components of the path.
+ // Since that field is urlencoded, we must urlencode the components of the path.
foreach (explode("/", $path) as $part) {
$encoded_array[] = rawurlencode($part);
}
$encoded_path = join("/", $encoded_array);
- $item = ORM::factory("item")
- ->where("relative_path_cache", "=", $encoded_path)
- ->find();
- if ($item->loaded()) {
- return $item;
+ if ($search_full_name) {
+ $item = ORM::factory("item")
+ ->where("relative_path_cache", "=", $encoded_path)
+ ->find();
+ // See if the item was found and if it should have been found.
+ if ($item->loaded() &&
+ (($var_subdir == "albums") || $item->is_photo() || $album_thumb)) {
+ return $item;
+ }
+ } else {
+ // Note that the below query uses LIKE with wildcard % at end, which is still sargable and
+ // therefore still takes advantage of the indexed relative_path_cache (i.e. still quick).
+ $item = ORM::factory("item")
+ ->where("relative_path_cache", "LIKE", Database::escape_for_like($encoded_path) . ".%")
+ ->find();
+ // See if the item was found and should be a jpg.
+ if ($item->loaded() &&
+ (($item->is_movie() && ($var_subdir == "thumbs")) ||
+ ($item->is_photo() && (preg_match("/^(.*)\.jpg$/", $item->name))))) {
+ return $item;
+ }
}
// Since the relative_path_cache field is a cache, it can be unavailable. If we don't find
// anything, fall back to checking the path the hard way.
$paths = explode("/", $path);
- foreach (ORM::factory("item")
- ->where("name", "=", end($paths))
- ->where("level", "=", count($paths) + 1)
- ->find_all() as $item) {
- if (urldecode($item->relative_path()) == $path) {
- return $item;
+ if ($search_full_name) {
+ foreach (ORM::factory("item")
+ ->where("name", "=", end($paths))
+ ->where("level", "=", count($paths) + 1)
+ ->find_all() as $item) {
+ // See if the item was found and if it should have been found.
+ if ((urldecode($item->relative_path()) == $path) &&
+ (($var_subdir == "albums") || $item->is_photo() || $album_thumb)) {
+ return $item;
+ }
+ }
+ } else {
+ foreach (ORM::factory("item")
+ ->where("name", "LIKE", Database::escape_for_like(end($paths)) . ".%")
+ ->where("level", "=", count($paths) + 1)
+ ->find_all() as $item) {
+ // Compare relative_path without extension (regexp same as legal_file::change_extension),
+ // see if it should be a jpg.
+ if ((preg_replace("/\.[^\.\/]*?$/", "", urldecode($item->relative_path())) == $path) &&
+ (($item->is_movie() && ($var_subdir == "thumbs")) ||
+ ($item->is_photo() && (preg_match("/^(.*)\.jpg$/", $item->name))))) {
+ return $item;
+ }
}
}
+ // Nothing found - return an empty item model.
return new Item_Model();
}
-
/**
* Locate an item using the URL. We assume that the url is in the form /a/b/c where each
* component matches up with an item slug. If there's no match, return an empty Item_Model
diff --git a/modules/gallery/helpers/legal_file.php b/modules/gallery/helpers/legal_file.php
index eb9c25de..9f02fe70 100644
--- a/modules/gallery/helpers/legal_file.php
+++ b/modules/gallery/helpers/legal_file.php
@@ -70,7 +70,8 @@ class legal_file_Core {
if (empty(self::$movie_types_by_extension)) {
$types_by_extension_wrapper = new stdClass();
$types_by_extension_wrapper->types_by_extension = array(
- "flv" => "video/x-flv", "mp4" => "video/mp4", "m4v" => "video/x-m4v");
+ "flv" => "video/x-flv", "mp4" => "video/mp4", "m4v" => "video/x-m4v",
+ "webm" => "video/webm", "ogv" => "video/ogg");
module::event("movie_types_by_extension", $types_by_extension_wrapper);
foreach (self::$blacklist as $key) {
unset($types_by_extension_wrapper->types_by_extension[$key]);
@@ -297,7 +298,7 @@ class legal_file_Core {
$filename = str_replace("/", "_", $filename);
$filename = str_replace("\\", "_", $filename);
- // Remove extra dots from the filename. This will also remove extraneous underscores.
+ // Remove extra dots from the filename. Also removes extraneous and leading/trailing underscores.
$filename = legal_file::smash_extensions($filename);
// It's possible that the filename has no base (e.g. ".jpg") - if so, give it a generic one.
@@ -307,4 +308,31 @@ class legal_file_Core {
return $filename;
}
+
+ /**
+ * Sanitize a directory name for an album. This returns a completely legal and valid
+ * directory name.
+ *
+ * @param string $dirname (with no parent directory)
+ * @return string sanitized dirname
+ */
+ static function sanitize_dirname($dirname) {
+ // It should be a dirname without a parent directory - remove all slashes (and backslashes).
+ $dirname = str_replace("/", "_", $dirname);
+ $dirname = str_replace("\\", "_", $dirname);
+
+ // Remove extraneous and leading/trailing underscores.
+ $dirname = preg_replace("/[_]+/", "_", $dirname);
+ $dirname = trim($dirname, "_");
+
+ // Remove any trailing dots.
+ $dirname = rtrim($dirname, ".");
+
+ // It's possible that the dirname is now empty - if so, give it a generic one.
+ if (empty($dirname)) {
+ $dirname = "album";
+ }
+
+ return $dirname;
+ }
}
diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php
index df258e87..1b6c8d1a 100644
--- a/modules/gallery/helpers/module.php
+++ b/modules/gallery/helpers/module.php
@@ -141,7 +141,7 @@ class module_Core {
$messages = array();
$installer_class = "{$module_name}_installer";
- if (method_exists($installer_class, "can_activate")) {
+ if (class_exists($installer_class) && method_exists($installer_class, "can_activate")) {
$messages = call_user_func(array($installer_class, "can_activate"));
}
@@ -173,7 +173,7 @@ class module_Core {
module::_add_to_path($module_name);
$installer_class = "{$module_name}_installer";
- if (method_exists($installer_class, "install")) {
+ if (class_exists($installer_class) && method_exists($installer_class, "install")) {
call_user_func_array(array($installer_class, "install"), array());
}
module::set_version($module_name, module::available()->$module_name->code_version);
@@ -226,7 +226,7 @@ class module_Core {
$version_before = module::get_version($module_name);
$installer_class = "{$module_name}_installer";
$available = module::available();
- if (method_exists($installer_class, "upgrade")) {
+ if (class_exists($installer_class) && method_exists($installer_class, "upgrade")) {
call_user_func_array(array($installer_class, "upgrade"), array($version_before));
} else {
if (isset($available->$module_name->code_version)) {
@@ -261,7 +261,7 @@ class module_Core {
module::_add_to_path($module_name);
$installer_class = "{$module_name}_installer";
- if (method_exists($installer_class, "activate")) {
+ if (class_exists($installer_class) && method_exists($installer_class, "activate")) {
call_user_func_array(array($installer_class, "activate"), array());
}
@@ -288,7 +288,7 @@ class module_Core {
*/
static function deactivate($module_name) {
$installer_class = "{$module_name}_installer";
- if (method_exists($installer_class, "deactivate")) {
+ if (class_exists($installer_class) && method_exists($installer_class, "deactivate")) {
call_user_func_array(array($installer_class, "deactivate"), array());
}
@@ -303,8 +303,25 @@ class module_Core {
block_manager::deactivate_blocks($module_name);
- log::success(
- "module", t("Deactivated module %module_name", array("module_name" => $module_name)));
+ if (module::info($module_name)) {
+ log::success(
+ "module", t("Deactivated module %module_name", array("module_name" => $module_name)));
+ } else {
+ log::success(
+ "module", t("Deactivated missing module %module_name", array("module_name" => $module_name)));
+ }
+ }
+
+ /**
+ * Deactivate modules that are unavailable or missing, yet still active.
+ * This happens when a user deletes a module without deactivating it.
+ */
+ static function deactivate_missing_modules() {
+ foreach (self::$modules as $module_name => $module) {
+ if (module::is_active($module_name) && !module::info($module_name)) {
+ module::deactivate($module_name);
+ }
+ }
}
/**
@@ -314,7 +331,7 @@ class module_Core {
*/
static function uninstall($module_name) {
$installer_class = "{$module_name}_installer";
- if (method_exists($installer_class, "uninstall")) {
+ if (class_exists($installer_class) && method_exists($installer_class, "uninstall")) {
call_user_func(array($installer_class, "uninstall"));
}
@@ -403,7 +420,7 @@ class module_Core {
continue;
}
$class = "{$module->name}_event";
- if (method_exists($class, $function)) {
+ if (class_exists($class) && method_exists($class, $function)) {
call_user_func_array(array($class, $function), $args);
}
}
@@ -411,7 +428,7 @@ class module_Core {
// Give the admin theme a chance to respond, if we're in admin mode.
if (theme::$is_admin) {
$class = theme::$admin_theme_name . "_event";
- if (method_exists($class, $function)) {
+ if (class_exists($class) && method_exists($class, $function)) {
call_user_func_array(array($class, $function), $args);
}
}
@@ -419,7 +436,7 @@ class module_Core {
// Give the site theme a chance to respond as well. It gets a chance even in admin mode, as
// long as the theme has an admin subdir.
$class = theme::$site_theme_name . "_event";
- if (method_exists($class, $function)) {
+ if (class_exists($class) && method_exists($class, $function)) {
call_user_func_array(array($class, $function), $args);
}
}
@@ -541,4 +558,37 @@ class module_Core {
static function get_version($module_name) {
return module::get($module_name)->version;
}
+
+ /**
+ * Check if obsolete modules are active and, if so, return a warning message.
+ * If none are found, return null.
+ */
+ static function get_obsolete_modules_message() {
+ // This is the obsolete modules list. Any active module that's on the list
+ // with version number at or below the one given will be considered obsolete.
+ // It is hard-coded here, and may be updated with future releases of Gallery.
+ $obsolete_modules = array("videos" => 4, "noffmpeg" => 1, "videodimensions" => 1,
+ "digibug" => 2);
+
+ // Before we check the active modules, deactivate any that are missing.
+ module::deactivate_missing_modules();
+
+ $modules_found = array();
+ foreach ($obsolete_modules as $module => $version) {
+ if (module::is_active($module) && (module::get_version($module) <= $version)) {
+ $modules_found[] = $module;
+ }
+ }
+
+ if ($modules_found) {
+ // Need this to be on one super-long line or else the localization scanner may not work.
+ // (ref: http://sourceforge.net/apps/trac/gallery/ticket/1321)
+ return t("Recent upgrades to Gallery have made the following modules obsolete: %modules. We recommend that you <a href=\"%url_mod\">deactivate</a> the module(s). For more information, please see the <a href=\"%url_doc\">documentation page</a>.",
+ array("modules" => implode(", ", $modules_found),
+ "url_mod" => url::site("admin/modules"),
+ "url_doc" => "http://codex.galleryproject.org/Gallery3:User_guide:Obsolete_modules"));
+ }
+
+ return null;
+ }
}
diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php
index eda478c7..4613df61 100644
--- a/modules/gallery/helpers/movie.php
+++ b/modules/gallery/helpers/movie.php
@@ -38,6 +38,7 @@ class movie_Core {
->error_messages(
"conflict", t("There is already a movie, photo or album with this name"))
->error_messages("no_slashes", t("The movie name can't contain a \"/\""))
+ ->error_messages("no_backslashes", t("The movie name can't contain a \"\\\""))
->error_messages("no_trailing_period", t("The movie name can't end in \".\""))
->error_messages("illegal_data_file_extension", t("You cannot change the movie file extension"))
->error_messages("required", t("You must provide a movie file name"))
@@ -138,7 +139,8 @@ class movie_Core {
* Return the path to the ffmpeg binary if one exists and is executable, or null.
*/
static function find_ffmpeg() {
- if (!($ffmpeg_path = module::get_var("gallery", "ffmpeg_path")) || !file_exists($ffmpeg_path)) {
+ if (!($ffmpeg_path = module::get_var("gallery", "ffmpeg_path")) ||
+ !@is_executable($ffmpeg_path)) {
$ffmpeg_path = system::find_binary(
"ffmpeg", module::get_var("gallery", "graphics_toolkit_path"));
module::set_var("gallery", "ffmpeg_path", $ffmpeg_path);
@@ -147,6 +149,34 @@ class movie_Core {
}
/**
+ * Return version number and build date of ffmpeg if found, empty string(s) if not. When using
+ * static builds that aren't official releases, the version numbers are strange, hence why the
+ * date can be useful.
+ */
+ static function get_ffmpeg_version() {
+ $ffmpeg = movie::find_ffmpeg();
+ if (empty($ffmpeg)) {
+ return array("", "");
+ }
+
+ // Find version using -h argument since -version wasn't available in early versions.
+ // To keep the preg_match searches quick, we'll trim the (otherwise long) result.
+ $cmd = escapeshellcmd($ffmpeg) . " -h 2>&1";
+ $result = substr(`$cmd`, 0, 1000);
+ if (preg_match("/ffmpeg version (\S+)/i", $result, $matches_version)) {
+ // Version number found - see if we can get the build date or copyright year as well.
+ if (preg_match("/built on (\S+\s\S+\s\S+)/i", $result, $matches_build_date)) {
+ return array(trim($matches_version[1], ","), trim($matches_build_date[1], ","));
+ } else if (preg_match("/copyright \S*\s?2000-(\d{4})/i", $result, $matches_copyright_date)) {
+ return array(trim($matches_version[1], ","), $matches_copyright_date[1]);
+ } else {
+ return array(trim($matches_version[1], ","), "");
+ }
+ }
+ return array("", "");
+ }
+
+ /**
* Return the width, height, mime_type, extension and duration of the given movie file.
* Metadata is first generated using ffmpeg (or set to defaults if it fails),
* then can be modified by other modules using movie_get_file_metadata events.
@@ -163,9 +193,7 @@ class movie_Core {
* -> return metadata from ffmpeg
* Input is *not* standard movie type that is *not* supported by ffmpeg but is legal
* -> return zero width, height, and duration; mime type and extension according to legal_file
- * Input is *not* standard movie type that is *not* supported by ffmpeg and is *not* legal
- * -> return zero width, height, and duration; null mime type and extension
- * Input is not readable or does not exist
+ * Input is illegal, unidentifiable, unreadable, or does not exist
* -> throw exception
* Note: movie_get_file_metadata events can change any of the above cases (except the last one).
*/
diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php
index 2d32f0d3..ecf81e66 100644
--- a/modules/gallery/helpers/photo.php
+++ b/modules/gallery/helpers/photo.php
@@ -35,6 +35,7 @@ class photo_Core {
$group->input("name")->label(t("Filename"))->value($photo->name)
->error_messages("conflict", t("There is already a movie, photo or album with this name"))
->error_messages("no_slashes", t("The photo name can't contain a \"/\""))
+ ->error_messages("no_backslashes", t("The photo name can't contain a \"\\\""))
->error_messages("no_trailing_period", t("The photo name can't end in \".\""))
->error_messages("illegal_data_file_extension", t("You cannot change the photo file extension"))
->error_messages("required", t("You must provide a photo file name"))
@@ -94,10 +95,8 @@ class photo_Core {
* Input is *not* standard photo type that is supported by getimagesize (e.g. tif, bmp...)
* -> return metadata from getimagesize()
* Input is *not* standard photo type that is *not* supported by getimagesize but is legal
- * -> return zero width and height, mime type and extension according to legal_file
- * Input is *not* standard photo type that is *not* supported by getimagesize and is *not* legal
- * -> return zero width and height, null mime type and extension
- * Input is not readable or does not exist
+ * -> return metadata if found by photo_get_file_metadata events
+ * Input is illegal, unidentifiable, unreadable, or does not exist
* -> throw exception
* Note: photo_get_file_metadata events can change any of the above cases (except the last one).
*/
diff --git a/modules/gallery/helpers/system.php b/modules/gallery/helpers/system.php
index e1398103..f0879d6a 100644
--- a/modules/gallery/helpers/system.php
+++ b/modules/gallery/helpers/system.php
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class system_Core {
+ private static $files_marked_for_deletion = array();
+
/**
* Return the path to an executable version of the named binary, or null.
* The paths are traversed in the following order:
@@ -45,6 +47,7 @@ class system_Core {
explode(":", module::get_var("gallery", "extra_binary_paths")));
foreach ($paths as $path) {
+ $path = rtrim($path, "/");
$candidate = "$path/$binary";
// @suppress errors below to avoid open_basedir issues
if (@file_exists($candidate)) {
@@ -66,8 +69,10 @@ class system_Core {
* This helper is similar to the built-in tempnam.
* It allows the caller to specify a prefix and an extension.
* It always places the file in TMPPATH.
+ * Unless specified with the $delete_later argument, it will be marked
+ * for deletion at shutdown using system::delete_later.
*/
- static function temp_filename($prefix="", $extension="") {
+ static function temp_filename($prefix="", $extension="", $delete_later=true) {
do {
$basename = tempnam(TMPPATH, $prefix);
if (!$basename) {
@@ -79,6 +84,30 @@ class system_Core {
@unlink($basename);
}
} while (!$success);
+
+ if ($delete_later) {
+ system::delete_later($filename);
+ }
+
return $filename;
}
-} \ No newline at end of file
+
+ /**
+ * Mark a file for deletion at shutdown time. This is useful for temp files, where we can delay
+ * the deletion time until shutdown to keep page load time quick.
+ */
+ static function delete_later($filename) {
+ self::$files_marked_for_deletion[] = $filename;
+ }
+
+ /**
+ * Delete all files marked using system::delete_later. This is called at gallery shutdown.
+ */
+ static function delete_marked_files() {
+ foreach (self::$files_marked_for_deletion as $filename) {
+ // We want to suppress all errors, as it's possible that some of these
+ // files may have been deleted/moved before we got here.
+ @unlink($filename);
+ }
+ }
+}
diff --git a/modules/gallery/helpers/task.php b/modules/gallery/helpers/task.php
index 32fd9739..5638faf4 100644
--- a/modules/gallery/helpers/task.php
+++ b/modules/gallery/helpers/task.php
@@ -25,7 +25,7 @@ class task_Core {
$tasks = array();
foreach (module::active() as $module) {
$class_name = "{$module->name}_task";
- if (method_exists($class_name, "available_tasks")) {
+ if (class_exists($class_name) && method_exists($class_name, "available_tasks")) {
foreach (call_user_func(array($class_name, "available_tasks")) as $task) {
$tasks[$task->callback] = $task;
}
diff --git a/modules/gallery/images/ffmpeg.png b/modules/gallery/images/ffmpeg.png
new file mode 100644
index 00000000..6be8b62a
--- /dev/null
+++ b/modules/gallery/images/ffmpeg.png
Binary files differ
diff --git a/modules/gallery/images/loading-small.gif b/modules/gallery/images/loading-small.gif
new file mode 100644
index 00000000..d0bce154
--- /dev/null
+++ b/modules/gallery/images/loading-small.gif
Binary files differ
diff --git a/modules/gallery/js/albums_form_add.js b/modules/gallery/js/albums_form_add.js
index a568f35d..55ad8ce6 100644
--- a/modules/gallery/js/albums_form_add.js
+++ b/modules/gallery/js/albums_form_add.js
@@ -1,23 +1,6 @@
-$("#g-add-album-form input[name=title]").change(
- function() {
- $("#g-add-album-form input[name=name]").attr(
- "value", $("#g-add-album-form input[name=title]").attr("value")
- .replace(/[\s\/]+/g, "-").replace(/\.+$/, ""));
- $("#g-add-album-form input[name=slug]").attr(
- "value", $("#g-add-album-form input[name=title]").attr("value")
- .replace(/[^A-Za-z0-9-_]+/g, "-")
- .replace(/^-+/, "")
- .replace(/-+$/, ""));
- });
-$("#g-add-album-form input[name=title]").keyup(
- function() {
- $("#g-add-album-form input[name=name]").attr(
- "value", $("#g-add-album-form input[name=title]").attr("value")
- .replace(/[\s\/]+/g, "-")
- .replace(/\.+$/, ""));
- $("#g-add-album-form input[name=slug]").attr(
- "value", $("#g-add-album-form input[name=title]").attr("value")
- .replace(/[^A-Za-z0-9-_]+/g, "-")
- .replace(/^-+/, "")
- .replace(/-+$/, ""));
- });
+$("#g-add-album-form input[name='title']").on("input keyup", function() {
+ $("#g-add-album-form input[name='name']").val(
+ $(this).val().replace(/[\s\/\\]+/g, "-").replace(/\.+$/, ""));
+ $("#g-add-album-form input[name='slug']").val(
+ $(this).val().replace(/[^A-Za-z0-9-_]+/g, "-").replace(/^-+/, "").replace(/-+$/, ""));
+});
diff --git a/modules/gallery/js/l10n_client.js b/modules/gallery/js/l10n_client.js
index 6d919c29..261461b9 100644
--- a/modules/gallery/js/l10n_client.js
+++ b/modules/gallery/js/l10n_client.js
@@ -121,11 +121,11 @@ jQuery.extend(Gallery, {
translation[form] = '';
}
$("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']")
- .attr('value', translation[form]);
+ .val(translation[form]);
$('#plural-' + form).removeClass('hidden');
}
} else {
- $('#l10n-edit-translation').attr('value', translation);
+ $('#l10n-edit-translation').val(translation);
$('#l10n-edit-translation').removeClass('hidden');
}
};
@@ -167,10 +167,10 @@ jQuery.extend(Gallery, {
text = source['one'];
}
$("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']")
- .attr('value', text);
+ .val(text);
}
} else {
- $('#l10n-edit-translation').attr('value', source);
+ $('#l10n-edit-translation').val(source);
}
}
@@ -240,7 +240,7 @@ Gallery.behaviors.l10nClient = function(context) {
});
// Custom listener for l10n_client livesearch
- $('#l10n-client #g-l10n-search').keyup(function(key) {
+ $('#l10n-client #g-l10n-search').on("input keyup", function(key) {
Gallery.l10nClient.filter($('#l10n-client #g-l10n-search').val());
});
@@ -264,11 +264,11 @@ Gallery.behaviors.l10nClient = function(context) {
if (is_plural) {
for (var i = 0; i < num_plural_forms; i++) {
var form = plural_forms[i];
- translation[form] = $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']").attr('value');
+ translation[form] = $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']").val();
is_non_empty = is_non_empty || translation[form];
}
} else {
- translation = $('#l10n-edit-translation').attr('value');
+ translation = $('#l10n-edit-translation').val();
is_non_empty = translation;
}
Gallery.l10nClient.setString(Gallery.l10nClient.selected, translation);
diff --git a/modules/gallery/libraries/Admin_View.php b/modules/gallery/libraries/Admin_View.php
index 83163868..ba348d7a 100644
--- a/modules/gallery/libraries/Admin_View.php
+++ b/modules/gallery/libraries/Admin_View.php
@@ -93,24 +93,52 @@ class Admin_View_Core extends Gallery_View {
case "body_attributes":
case "html_attributes":
$blocks = array();
+ if (method_exists("gallery_theme", $function)) {
+ switch (count($args)) {
+ case 0:
+ $blocks[] = gallery_theme::$function($this);
+ break;
+ case 1:
+ $blocks[] = gallery_theme::$function($this, $args[0]);
+ break;
+ case 2:
+ $blocks[] = gallery_theme::$function($this, $args[0], $args[1]);
+ break;
+ default:
+ $blocks[] = call_user_func_array(
+ array("gallery_theme", $function),
+ array_merge(array($this), $args));
+ }
+ }
+
foreach (module::active() as $module) {
+ if ($module->name == "gallery") {
+ continue;
+ }
$helper_class = "{$module->name}_theme";
- if (method_exists($helper_class, $function)) {
+ if (class_exists($helper_class) && method_exists($helper_class, $function)) {
$blocks[] = call_user_func_array(
array($helper_class, $function),
array_merge(array($this), $args));
}
}
+ $helper_class = theme::$admin_theme_name . "_theme";
+ if (class_exists($helper_class) && method_exists($helper_class, $function)) {
+ $blocks[] = call_user_func_array(
+ array($helper_class, $function),
+ array_merge(array($this), $args));
+ }
+
if (Session::instance()->get("debug")) {
- if ($function != "admin_head") {
+ if ($function != "admin_head" && $function != "body_attributes") {
array_unshift(
- $blocks, "<div class=\"g-annotated-theme-block g-annotated-theme-block_$function\">" .
+ $blocks,
+ "<div class=\"g-annotated-theme-block g-annotated-theme-block_$function g-clear-fix\">" .
"<div class=\"title\">$function</div>");
$blocks[] = "</div>";
}
}
-
return implode("\n", $blocks);
default:
diff --git a/modules/gallery/libraries/Gallery_View.php b/modules/gallery/libraries/Gallery_View.php
index 8f02b53c..3f59db6a 100644
--- a/modules/gallery/libraries/Gallery_View.php
+++ b/modules/gallery/libraries/Gallery_View.php
@@ -82,10 +82,9 @@ class Gallery_View_Core extends View {
* @param $types a comma separated list of types to combine, eg "script,css"
*/
public function start_combining($types) {
- if (gallery::allow_css_and_js_combining()) {
- foreach (explode(",", $types) as $type) {
- $this->combine_queue[$type] = array();
- }
+ foreach (explode(",", $types) as $type) {
+ // Initialize the core group so it gets included first.
+ $this->combine_queue[$type] = array("core" => array());
}
}
@@ -135,70 +134,93 @@ class Gallery_View_Core extends View {
/**
* Combine a series of files into a single one and cache it in the database.
* @param $type the data type (script or css)
- * @param $group the group of scripts or css we want
+ * @param $group the group of scripts or css we want (null will combine all groups)
*/
- public function get_combined($type, $group="core") {
- $links = array();
-
- if (empty($this->combine_queue[$type][$group])) {
- return;
+ public function get_combined($type, $group=null) {
+ if (is_null($group)) {
+ $groups = array_keys($this->combine_queue[$type]);
+ } else {
+ $groups = array($group);
}
- // 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(""));
+ $buf = "";
+ foreach ($groups as $group) {
+ if (empty($this->combine_queue[$type][$group])) {
+ continue;
+ }
- foreach (array_keys($this->combine_queue[$type][$group]) as $path) {
- $stats = stat($path);
- // 7 == size, 9 == mtime, see http://php.net/stat
- $key[] = "$path $stats[7] $stats[9]";
- }
+ // 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(""));
+ foreach (array_keys($this->combine_queue[$type][$group]) as $path) {
+ $stats = stat($path);
+ // 7 == size, 9 == mtime, see http://php.net/stat
+ $key[] = "$path $stats[7] $stats[9]";
+ }
+ $key = md5(join(" ", $key));
- $key = md5(join(" ", $key));
- $cache = Cache::instance();
- $contents = $cache->get($key);
+ if (gallery::allow_css_and_js_combining()) {
+ // Combine enabled - if we're at the start of the buffer, add a comment.
+ if (!$buf) {
+ $type_text = ($type == "css") ? "CSS" : "JS";
+ $buf .= "<!-- LOOKING FOR YOUR $type_text? It's all been combined into the link(s) below -->\n";
+ }
- if (empty($contents)) {
- $combine_data = new stdClass();
- $combine_data->type = $type;
- $combine_data->contents = $this->combine_queue[$type][$group];
- module::event("before_combine", $combine_data);
+ $cache = Cache::instance();
+ $contents = $cache->get($key);
- $contents = "";
- foreach (array_keys($this->combine_queue[$type][$group]) as $path) {
- if ($type == "css") {
- $contents .= "/* $path */\n" . $this->process_css($path) . "\n";
- } else {
- $contents .= "/* $path */\n" . file_get_contents($path) . "\n";
- }
- }
+ if (empty($contents)) {
+ $combine_data = new stdClass();
+ $combine_data->type = $type;
+ $combine_data->contents = $this->combine_queue[$type][$group];
+ module::event("before_combine", $combine_data);
- $combine_data = new stdClass();
- $combine_data->type = $type;
- $combine_data->contents = $contents;
- module::event("after_combine", $combine_data);
+ $contents = "";
+ foreach (array_keys($this->combine_queue[$type][$group]) as $path) {
+ if ($type == "css") {
+ $contents .= "/* $path */\n" . $this->process_css($path) . "\n";
+ } else {
+ $contents .= "/* $path */\n" . file_get_contents($path) . "\n";
+ }
+ }
- $cache->set($key, $combine_data->contents, array($type), 30 * 84600);
+ $combine_data = new stdClass();
+ $combine_data->type = $type;
+ $combine_data->contents = $contents;
+ module::event("after_combine", $combine_data);
- $use_gzip = function_exists("gzencode") &&
- (int) ini_get("zlib.output_compression") === 0;
- if ($use_gzip) {
- $cache->set("{$key}_gz", gzencode($combine_data->contents, 9, FORCE_GZIP),
- array($type, "gzip"), 30 * 84600);
- }
+ $cache->set($key, $combine_data->contents, array($type), 30 * 84600);
- }
+ $use_gzip = function_exists("gzencode") &&
+ (int) ini_get("zlib.output_compression") === 0;
+ if ($use_gzip) {
+ $cache->set("{$key}_gz", gzencode($combine_data->contents, 9, FORCE_GZIP),
+ array($type, "gzip"), 30 * 84600);
+ }
+ }
- unset($this->combine_queue[$type][$group]);
- if (empty($this->combine_queue[$type])) {
- unset($this->combine_queue[$type]);
- }
+ if ($type == "css") {
+ $buf .= html::stylesheet("combined/css/$key", "screen,print,projection", true);
+ } else {
+ $buf .= html::script("combined/javascript/$key", true);
+ }
+ } else {
+ // Don't combine - just return the CSS and JS links (with the key as a cache buster).
+ foreach (array_keys($this->combine_queue[$type][$group]) as $path) {
+ if ($type == "css") {
+ $buf .= html::stylesheet("$path?m=$key", "screen,print,projection", false);
+ } else {
+ $buf .= html::script("$path?m=$key", false);
+ }
+ }
+ }
- if ($type == "css") {
- return html::stylesheet("combined/css/$key", "screen,print,projection", true);
- } else {
- return html::script("combined/javascript/$key", true);
+ unset($this->combine_queue[$type][$group]);
+ if (empty($this->combine_queue[$type])) {
+ unset($this->combine_queue[$type]);
+ }
}
+ return $buf;
}
/**
diff --git a/modules/gallery/libraries/IdentityProvider.php b/modules/gallery/libraries/IdentityProvider.php
index 23368a6a..525e1695 100644
--- a/modules/gallery/libraries/IdentityProvider.php
+++ b/modules/gallery/libraries/IdentityProvider.php
@@ -81,7 +81,8 @@ class IdentityProvider_Core {
module::set_var("gallery", "identity_provider", $new_provider);
- if (method_exists("{$new_provider}_installer", "initialize")) {
+ if (class_exists("{$new_provider}_installer") &&
+ method_exists("{$new_provider}_installer", "initialize")) {
call_user_func("{$new_provider}_installer::initialize");
}
diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php
index 31e9d31b..179cbd41 100644
--- a/modules/gallery/libraries/SafeString.php
+++ b/modules/gallery/libraries/SafeString.php
@@ -153,7 +153,7 @@ class SafeString_Core {
* Purify the string, removing any potentially malicious or unsafe HTML / JavaScript.
*/
private static function _purify_for_html($dirty_html) {
- if (method_exists("purifier", "purify")) {
+ if (class_exists("purifier") && method_exists("purifier", "purify")) {
return purifier::purify($dirty_html);
} else {
return self::_escape_for_html($dirty_html);
diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php
index 986fc8a2..fbc58258 100644
--- a/modules/gallery/libraries/Theme_View.php
+++ b/modules/gallery/libraries/Theme_View.php
@@ -58,23 +58,37 @@ class Theme_View_Core extends Gallery_View {
}
/**
- * Proportion of the current thumb_size's to default
+ * Proportion of the current thumb_size's to default.
+ *
+ * Themes can optionally use the $dimension parameter to choose which of the album's
+ * children will be used to determine the proportion. If set, the proportion will be
+ * calculated based on the child item with the largest width or height.
+ *
* @param object Item_Model (optional) check the proportions for this item
+ * @param int (optional) minimum thumbnail width
+ * @param string (optional) "width" or "height"
* @return int
*/
- public function thumb_proportion($item=null) {
- // If the item is an album with children, grab the first item in that album instead. We're
+ public function thumb_proportion($item=null, $minimum_size=0, $dimension=null) {
+ if (!in_array($dimension, array("height", "width"))) {
+ $dimension = null;
+ }
+
+ // If the item is an album with children, grab an item from that album instead. We're
// interested in the size of the thumbnails in this album, not the thumbnail of the
// album itself.
if ($item && $item->is_album() && $item->children_count()) {
- $item = $item->children(1)->current();
+ $orderBy = (is_null($dimension)) ? array()
+ : array("thumb_".$dimension => "desc");
+
+ $item = $item->children(1, null, array(), $orderBy)->current();
}
// By default we have a globally fixed thumbnail size In core code, we just return a fixed
// proportion based on the global thumbnail size, but since modules can override that, we
// return the actual proportions when we have them.
if ($item && $item->has_thumb()) {
- return max($item->thumb_width, $item->thumb_height) / 200;
+ return max($item->thumb_width, $item->thumb_height, $minimum_size) / 200;
} else {
// @TODO change the 200 to a theme supplied value when and if we come up with an
// API to allow the theme to set defaults.
@@ -89,7 +103,7 @@ class Theme_View_Core extends Gallery_View {
public function siblings($limit=null, $offset=null) {
return call_user_func_array(
$this->siblings_callback[0],
- array_merge($this->siblings_callback[1], array($offset, $limit)));
+ array_merge($this->siblings_callback[1], array($limit, $offset)));
}
public function tag() {
@@ -239,7 +253,7 @@ class Theme_View_Core extends Gallery_View {
continue;
}
$helper_class = "{$module->name}_theme";
- if (method_exists($helper_class, $function)) {
+ if (class_exists($helper_class) && method_exists($helper_class, $function)) {
$blocks[] = call_user_func_array(
array($helper_class, $function),
array_merge(array($this), $args));
@@ -247,7 +261,7 @@ class Theme_View_Core extends Gallery_View {
}
$helper_class = theme::$site_theme_name . "_theme";
- if (method_exists($helper_class, $function)) {
+ if (class_exists($helper_class) && method_exists($helper_class, $function)) {
$blocks[] = call_user_func_array(
array($helper_class, $function),
array_merge(array($this), $args));
diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php
index 43b9a292..1d4f35da 100644
--- a/modules/gallery/models/item.php
+++ b/modules/gallery/models/item.php
@@ -365,14 +365,20 @@ class Item_Model_Core extends ORM_MPTT {
$this->weight = item::get_max_weight();
}
- // Process the data file info.
- if (isset($this->data_file)) {
- $this->_process_data_file_info();
- } else if (!$this->is_album()) {
- // Unless it's an album, new items must have a data file.
- $this->data_file_error = true;
+ if ($this->is_album()) {
+ // Sanitize the album name.
+ $this->name = legal_file::sanitize_dirname($this->name);
+ } else {
+ // Process the data file info. This also sanitizes the item name.
+ if (isset($this->data_file)) {
+ $this->_process_data_file_info();
+ } else {
+ // New photos and movies must have a data file.
+ $this->data_file_error = true;
+ }
}
+
// Make an url friendly slug from the name, if necessary
if (empty($this->slug)) {
$this->slug = item::convert_filename_to_slug(pathinfo($this->name, PATHINFO_FILENAME));
@@ -416,7 +422,7 @@ class Item_Model_Core extends ORM_MPTT {
module::event("item_created", $this);
} else {
// Update an existing item
- module::event("item_before_update", $item);
+ module::event("item_before_update", $this);
// If any significant fields have changed, load up a copy of the original item and
// keep it around.
@@ -437,6 +443,11 @@ class Item_Model_Core extends ORM_MPTT {
pathinfo($original->name, PATHINFO_EXTENSION), $this->type);
}
+ // If an album's name changed, sanitize it.
+ if ($this->is_album() && array_key_exists("name", $this->changed)) {
+ $this->name = legal_file::sanitize_dirname($this->name);
+ }
+
// If an album's cover has changed (or been removed), delete any existing album cover,
// reset the thumb metadata, and mark the thumb as dirty.
if (array_key_exists("album_cover_item_id", $this->changed) && $this->is_album()) {
@@ -737,40 +748,42 @@ class Item_Model_Core extends ORM_MPTT {
}
/**
- * Return a view for movies. By default this is a Flowplayer v3 <script> tag, but
- * movie_img events can override this and provide their own player/view. If no player/view
- * is found and the movie is unsupported by Flowplayer v3, this returns a simple download link.
+ * Return a view for movies. By default, this uses MediaElementPlayer on an HTML5-compliant
+ * <video> object, but movie_img events can override this and provide their own player/view.
+ * If none are found and the player can't play the movie, this returns a simple download link.
* @param array $extra_attrs
* @return string
*/
public function movie_img($extra_attrs) {
- $max_size = module::get_var("gallery", "resize_size", 640);
+ $player_width = module::get_var("gallery", "resize_size", 640);
$width = $this->width;
$height = $this->height;
if ($width == 0 || $height == 0) {
- // Not set correctly, likely because ffmpeg isn't available. Making the window 0x0 causes the
- // video to be effectively unviewable. So, let's guess: set width to max_size and guess a
- // height (using 4:3 aspect ratio). Once the video metadata is loaded, js in
- // movieplayer.html.php will correct these values.
- $width = $max_size;
+ // Not set correctly, likely because FFmpeg isn't available. Making the window 0x0 causes the
+ // player to be unviewable during loading. So, let's guess: set width to player_width and
+ // guess a height (using 4:3 aspect ratio). Once the video metadata is loaded, the player
+ // will correct these values.
+ $width = $player_width;
$height = ceil($width * 3/4);
}
- $attrs = array_merge(array("id" => "g-item-id-{$this->id}"), $extra_attrs,
- array("class" => "g-movie"));
+ $div_attrs = array_merge(array("id" => "g-item-id-{$this->id}"), $extra_attrs,
+ array("class" => "g-movie", "style" => "width: {$player_width}px;"));
// Run movie_img events, which can either:
- // - generate a view, which is used in place of the standard Flowplayer v3 player
+ // - generate a view, which is used in place of the standard MediaElementPlayer
// (use view variable)
- // - alter the arguments sent to the standard player
- // (use fp_params and fp_config variables)
+ // - change the file sent to the player
+ // (use width, height, url, and filename variables)
+ // - alter the arguments sent to the player
+ // (use video_attrs and player_options variables)
$movie_img = new stdClass();
- $movie_img->max_size = $max_size;
$movie_img->width = $width;
$movie_img->height = $height;
- $movie_img->attrs = $attrs;
$movie_img->url = $this->file_url(true);
- $movie_img->fp_params = array(); // additional Flowplayer params values (will be json encoded)
- $movie_img->fp_config = array(); // additional Flowplayer config values (will be json encoded)
+ $movie_img->filename = $this->name;
+ $movie_img->div_attrs = $div_attrs; // attrs for the outer .g-movie <div>
+ $movie_img->video_attrs = array(); // add'l <video> attrs
+ $movie_img->player_options = array(); // add'l MediaElementPlayer options (will be json encoded)
$movie_img->view = array();
module::event("movie_img", $movie_img, $this);
@@ -778,26 +791,26 @@ class Item_Model_Core extends ORM_MPTT {
// View generated - use it
$view = implode("\n", $movie_img->view);
} else {
- // View NOT generated - see if filetype supported by Flowplayer v3
- // Note that the extension list below is hard-coded and doesn't use the legal_file helper
- // since anything else will not work in Flowplayer v3.
- if (in_array(strtolower(pathinfo($this->name, PATHINFO_EXTENSION)),
- array("flv", "mp4", "m4v", "mov", "f4v"))) {
- // Filetype supported by Flowplayer v3 - use it (default)
+ // View not generated - see if the filetype is supported by MediaElementPlayer.
+ // Note that the extension list below doesn't use the legal_file helper but rather
+ // is hard-coded based on player specifications.
+ $extension = strtolower(pathinfo($movie_img->filename, PATHINFO_EXTENSION));
+ if (in_array($extension, array("webm", "ogv", "mp4", "flv", "m4v", "mov", "f4v", "wmv"))) {
+ // Filetype supported by MediaElementPlayer - use it (default)
$view = new View("movieplayer.html");
- $view->max_size = $movie_img->max_size;
$view->width = $movie_img->width;
$view->height = $movie_img->height;
- $view->attrs = $movie_img->attrs;
- $view->url = $movie_img->url;
- $view->fp_params = $movie_img->fp_params;
- $view->fp_config = $movie_img->fp_config;
+ $view->div_attrs = $movie_img->div_attrs;
+ $view->video_attrs = array_merge(array("controls" => "controls", "autoplay" => "autoplay",
+ "style" => "max-width: 100%"), $movie_img->video_attrs);
+ $view->source_attrs = array("type" => legal_file::get_movie_types_by_extension($extension),
+ "src" => $movie_img->url);
+ $view->player_options = $movie_img->player_options;
} else {
- // Filetype NOT supported by Flowplayer v3 - display download link
- $attrs = array_merge($attrs, array("style" => "width: {$max_size}px;",
- "download" => $this->name, // forces download (HTML5 only)
- "class" => "g-movie g-movie-download-link"));
- $view = html::anchor($this->file_url(true), t("Click here to download item."), $attrs);
+ // Filetype not supported by MediaElementPlayer - display download link
+ $div_attrs["class"] .= " g-movie-download-link"; // add class
+ $div_attrs["download"] = $movie_img->filename; // force download (HTML5 only)
+ $view = html::anchor($movie_img->url, t("Click here to download item."), $div_attrs);
}
}
return $view;
@@ -887,12 +900,17 @@ class Item_Model_Core extends ORM_MPTT {
}
/**
- * Validate that the desired slug does not conflict.
+ * Validate the item slug. It can return the following error messages:
+ * - not_url_safe: has illegal characters
+ * - conflict: has conflicting slug
+ * - reserved (items in root only): has same slug as a controller
*/
public function valid_slug(Validation $v, $field) {
if (preg_match("/[^A-Za-z0-9-_]/", $this->slug)) {
$v->add_error("slug", "not_url_safe");
- } else if (db::build()
+ }
+
+ if (db::build()
->from("items")
->where("parent_id", "=", $this->parent_id)
->where("id", "<>", $this->id)
@@ -900,11 +918,20 @@ class Item_Model_Core extends ORM_MPTT {
->count_records()) {
$v->add_error("slug", "conflict");
}
+
+ if ($this->parent_id == 1 && Kohana::auto_load("{$this->slug}_Controller")) {
+ $v->add_error("slug", "reserved");
+ return;
+ }
}
/**
- * Validate the item name. It can't conflict with other names, can't contain slashes or
- * trailing periods.
+ * Validate the item name. It can return the following error messages:
+ * - no_slashes: contains slashes
+ * - no_backslashes: contains backslashes
+ * - no_trailing_period: has a trailing period
+ * - illegal_data_file_extension (non-albums only): has double, no, or illegal extension
+ * - conflict: has conflicting name
*/
public function valid_name(Validation $v, $field) {
if (strpos($this->name, "/") !== false) {
@@ -912,18 +939,23 @@ class Item_Model_Core extends ORM_MPTT {
return;
}
- if (rtrim($this->name, ".") !== $this->name) {
- $v->add_error("name", "no_trailing_period");
+ if (strpos($this->name, "\\") !== false) {
+ $v->add_error("name", "no_backslashes");
return;
}
- // Do not accept files with double extensions, they can cause problems on some
- // versions of Apache.
- if (!$this->is_album() && substr_count($this->name, ".") > 1) {
- $v->add_error("name", "illegal_data_file_extension");
+ if (rtrim($this->name, ".") !== $this->name) {
+ $v->add_error("name", "no_trailing_period");
+ return;
}
if ($this->is_movie() || $this->is_photo()) {
+ if (substr_count($this->name, ".") > 1) {
+ // Do not accept files with double extensions, as they can
+ // cause problems on some versions of Apache.
+ $v->add_error("name", "illegal_data_file_extension");
+ }
+
$ext = pathinfo($this->name, PATHINFO_EXTENSION);
if (!$this->loaded() && !$ext) {
@@ -965,11 +997,6 @@ class Item_Model_Core extends ORM_MPTT {
return;
}
}
-
- if ($this->parent_id == 1 && Kohana::auto_load("{$this->slug}_Controller")) {
- $v->add_error("slug", "reserved");
- return;
- }
}
/**
diff --git a/modules/gallery/module.info b/modules/gallery/module.info
index 2383ec3c..49023e45 100644
--- a/modules/gallery/module.info
+++ b/modules/gallery/module.info
@@ -1,6 +1,6 @@
name = "Gallery 3"
description = "Gallery core application"
-version = 56
+version = 58
author_name = "Gallery Team"
author_url = "http://codex.galleryproject.org/Gallery:Team"
info_url = "http://codex.galleryproject.org/Gallery3:Modules:gallery"
diff --git a/modules/gallery/tests/File_Proxy_Controller_Test.php b/modules/gallery/tests/File_Proxy_Controller_Test.php
index 562100e4..06068d62 100644
--- a/modules/gallery/tests/File_Proxy_Controller_Test.php
+++ b/modules/gallery/tests/File_Proxy_Controller_Test.php
@@ -66,7 +66,7 @@ class File_Proxy_Controller_Test extends Gallery_Unit_Test_Case {
public function movie_thumbnails_are_jpgs_test() {
$movie = test::random_movie();
$name = legal_file::change_extension($movie->name, "jpg");
- $_SERVER["REQUEST_URI"] = url::file("var/thumbs/{$movie->name}");
+ $_SERVER["REQUEST_URI"] = url::file("var/thumbs/$name");
$controller = new File_Proxy_Controller();
$this->assert_same($movie->thumb_path(), $controller->__call("", array()));
}
diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php
index 476faa5a..4643e6fd 100644
--- a/modules/gallery/tests/Html_Helper_Test.php
+++ b/modules/gallery/tests/Html_Helper_Test.php
@@ -27,7 +27,7 @@ class Html_Helper_Test extends Gallery_Unit_Test_Case {
public function purify_test() {
$safe_string = html::purify("hello <p >world</p>");
- $expected = method_exists("purifier", "purify")
+ $expected = (class_exists("purifier") && method_exists("purifier", "purify"))
? "hello <p>world</p>"
: "hello &lt;p &gt;world&lt;/p&gt;";
$this->assert_equal($expected, $safe_string->unescaped());
diff --git a/modules/gallery/tests/Item_Helper_Test.php b/modules/gallery/tests/Item_Helper_Test.php
index f5b99bec..f4995c53 100644
--- a/modules/gallery/tests/Item_Helper_Test.php
+++ b/modules/gallery/tests/Item_Helper_Test.php
@@ -164,11 +164,9 @@ class Item_Helper_Test extends Gallery_Unit_Test_Case {
$this->assert_same(item::root()->id, item::find_by_path("")->id);
// Verify that we don't get confused by the part names, using the fallback code.
- db::build()
- ->update("items")
- ->set(array("relative_path_cache" => null))
- ->where("id", "IN", array($level3->id, $level3b->id))
- ->execute();
+ self::_remove_relative_path_caches();
+ self::_remove_relative_path_caches();
+
$this->assert_same(
$level3->id,
item::find_by_path("{$level1->name}/{$level2->name}/{$level3->name}")->id);
@@ -180,11 +178,154 @@ class Item_Helper_Test extends Gallery_Unit_Test_Case {
// Verify that we don't get false positives
$this->assert_false(
item::find_by_path("foo/bar/baz")->loaded());
+ }
- // Verify that the fallback code works
- $this->assert_same(
- $level3b->id,
- item::find_by_path("{$level1->name}/{$level2b->name}/{$level3b->name}")->id);
+ public function find_by_path_with_jpg_test() {
+ $parent = test::random_album();
+ $jpg = test::random_photo($parent);
+
+ $jpg_path = "{$parent->name}/{$jpg->name}";
+ $flv_path = legal_file::change_extension($jpg_path, "flv");
+
+ // Check normal operation.
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "albums")->id);
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "resizes")->id);
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "thumbs")->id);
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path)->id);
+
+ // Check that we don't get false positives.
+ $this->assert_equal(null, item::find_by_path($flv_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path, "resizes")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path)->id);
+
+ // Check normal operation without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "albums")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "resizes")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path, "thumbs")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($jpg->id, item::find_by_path($jpg_path)->id);
+
+ // Check that we don't get false positives without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal(null, item::find_by_path($flv_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path, "resizes")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path)->id);
+ }
+
+ public function find_by_path_with_png_test() {
+ $parent = test::random_album();
+ $png = test::random_photo_unsaved($parent);
+ $png->set_data_file(MODPATH . "gallery/images/graphicsmagick.png");
+ $png->save();
+
+ $png_path = "{$parent->name}/{$png->name}";
+ $jpg_path = legal_file::change_extension($png_path, "jpg");
+
+ // Check normal operation.
+ $this->assert_equal($png->id, item::find_by_path($png_path, "albums")->id);
+ $this->assert_equal($png->id, item::find_by_path($png_path, "resizes")->id);
+ $this->assert_equal($png->id, item::find_by_path($png_path, "thumbs")->id);
+ $this->assert_equal($png->id, item::find_by_path($png_path)->id);
+
+ // Check that we don't get false positives.
+ $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path, "resizes")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path)->id);
+
+ // Check normal operation without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal($png->id, item::find_by_path($png_path, "albums")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($png->id, item::find_by_path($png_path, "resizes")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($png->id, item::find_by_path($png_path, "thumbs")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($png->id, item::find_by_path($png_path)->id);
+
+ // Check that we don't get false positives without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path, "resizes")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path)->id);
+ }
+
+ public function find_by_path_with_flv_test() {
+ $parent = test::random_album();
+ $flv = test::random_movie($parent);
+
+ $flv_path = "{$parent->name}/{$flv->name}";
+ $jpg_path = legal_file::change_extension($flv_path, "jpg");
+
+ // Check normal operation.
+ $this->assert_equal($flv->id, item::find_by_path($flv_path, "albums")->id);
+ $this->assert_equal($flv->id, item::find_by_path($jpg_path, "thumbs")->id);
+ $this->assert_equal($flv->id, item::find_by_path($flv_path)->id);
+
+ // Check that we don't get false positives.
+ $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path)->id);
+
+ // Check normal operation without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal($flv->id, item::find_by_path($flv_path, "albums")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($flv->id, item::find_by_path($jpg_path, "thumbs")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($flv->id, item::find_by_path($flv_path)->id);
+
+ // Check that we don't get false positives without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal(null, item::find_by_path($jpg_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($flv_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($jpg_path)->id);
+ }
+
+ public function find_by_path_with_album_test() {
+ $parent = test::random_album();
+ $album = test::random_movie($parent);
+
+ $album_path = "{$parent->name}/{$album->name}";
+ $thumb_path = "{$album_path}/.album.jpg";
+
+ // Check normal operation.
+ $this->assert_equal($album->id, item::find_by_path($album_path, "albums")->id);
+ $this->assert_equal($album->id, item::find_by_path($thumb_path, "thumbs")->id);
+ $this->assert_equal($album->id, item::find_by_path($album_path)->id);
+
+ // Check that we don't get false positives.
+ $this->assert_equal(null, item::find_by_path($thumb_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($album_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($thumb_path)->id);
+
+ // Check normal operation without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal($album->id, item::find_by_path($album_path, "albums")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($album->id, item::find_by_path($thumb_path, "thumbs")->id);
+ self::_remove_relative_path_caches();
+ $this->assert_equal($album->id, item::find_by_path($album_path)->id);
+
+ // Check that we don't get false positives without relative path cache.
+ self::_remove_relative_path_caches();
+ $this->assert_equal(null, item::find_by_path($thumb_path, "albums")->id);
+ $this->assert_equal(null, item::find_by_path($album_path, "thumbs")->id);
+ $this->assert_equal(null, item::find_by_path($thumb_path)->id);
+ }
+
+ private function _remove_relative_path_caches() {
+ // This gets used *many* times in the find_by_path tests above to check the fallback code.
+ db::build()
+ ->update("items")
+ ->set("relative_path_cache", null)
+ ->execute();
}
public function find_by_relative_url_test() {
diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php
index fcb5c2ad..b6849413 100644
--- a/modules/gallery/tests/Item_Model_Test.php
+++ b/modules/gallery/tests/Item_Model_Test.php
@@ -124,11 +124,124 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$this->assert_equal($fullsize_file, file_get_contents($photo->file_path()));
}
- public function item_rename_wont_accept_slash_test() {
- $item = test::random_photo();
+ public function photo_rename_wont_accept_slash_test() {
+ $item = test::random_photo_unsaved();
$item->name = "/no_slashes/allowed/";
+ // Should fail on validate.
+ try {
+ $item->validate();
+ $this->assert_true(false, "Shouldn't get here");
+ } catch (ORM_Validation_Exception $e) {
+ $errors = $e->validation->errors();
+ $this->assert_same("no_slashes", $errors["name"]);
+ }
+ // Should be corrected on save.
$item->save();
$this->assert_equal("no_slashes_allowed.jpg", $item->name);
+ // Should be corrected on update.
+ $item->name = "/no_slashes/allowed/";
+ $item->save();
+ $this->assert_equal("no_slashes_allowed.jpg", $item->name);
+ }
+
+ public function photo_rename_wont_accept_backslash_test() {
+ $item = test::random_photo_unsaved();
+ $item->name = "\\no_backslashes\\allowed\\";
+ // Should fail on validate.
+ try {
+ $item->validate();
+ $this->assert_true(false, "Shouldn't get here");
+ } catch (ORM_Validation_Exception $e) {
+ $errors = $e->validation->errors();
+ $this->assert_same("no_backslashes", $errors["name"]);
+ }
+ // Should be corrected on save.
+ $item->save();
+ $this->assert_equal("no_backslashes_allowed.jpg", $item->name);
+ // Should be corrected on update.
+ $item->name = "\\no_backslashes\\allowed\\";
+ $item->save();
+ $this->assert_equal("no_backslashes_allowed.jpg", $item->name);
+ }
+
+ public function photo_rename_wont_accept_trailing_period_test() {
+ $item = test::random_photo_unsaved();
+ $item->name = "no_trailing_period_allowed.";
+ // Should fail on validate.
+ try {
+ $item->validate();
+ $this->assert_true(false, "Shouldn't get here");
+ } catch (ORM_Validation_Exception $e) {
+ $errors = $e->validation->errors();
+ $this->assert_same("no_trailing_period", $errors["name"]);
+ }
+ // Should be corrected on save.
+ $item->save();
+ $this->assert_equal("no_trailing_period_allowed.jpg", $item->name);
+ // Should be corrected on update.
+ $item->name = "no_trailing_period_allowed.";
+ $item->save();
+ $this->assert_equal("no_trailing_period_allowed.jpg", $item->name);
+ }
+
+ public function album_rename_wont_accept_slash_test() {
+ $item = test::random_album_unsaved();
+ $item->name = "/no_album_slashes/allowed/";
+ // Should fail on validate.
+ try {
+ $item->validate();
+ $this->assert_true(false, "Shouldn't get here");
+ } catch (ORM_Validation_Exception $e) {
+ $errors = $e->validation->errors();
+ $this->assert_same("no_slashes", $errors["name"]);
+ }
+ // Should be corrected on save.
+ $item->save();
+ $this->assert_equal("no_album_slashes_allowed", $item->name);
+ // Should be corrected on update.
+ $item->name = "/no_album_slashes/allowed/";
+ $item->save();
+ $this->assert_equal("no_album_slashes_allowed", $item->name);
+ }
+
+ public function album_rename_wont_accept_backslash_test() {
+ $item = test::random_album_unsaved();
+ $item->name = "\\no_album_backslashes\\allowed\\";
+ // Should fail on validate.
+ try {
+ $item->validate();
+ $this->assert_true(false, "Shouldn't get here");
+ } catch (ORM_Validation_Exception $e) {
+ $errors = $e->validation->errors();
+ $this->assert_same("no_backslashes", $errors["name"]);
+ }
+ // Should be corrected on save.
+ $item->save();
+ $this->assert_equal("no_album_backslashes_allowed", $item->name);
+ // Should be corrected on update.
+ $item->name = "\\no_album_backslashes\\allowed\\";
+ $item->save();
+ $this->assert_equal("no_album_backslashes_allowed", $item->name);
+ }
+
+ public function album_rename_wont_accept_trailing_period_test() {
+ $item = test::random_album_unsaved();
+ $item->name = ".no_trailing_period.allowed.";
+ // Should fail on validate.
+ try {
+ $item->validate();
+ $this->assert_true(false, "Shouldn't get here");
+ } catch (ORM_Validation_Exception $e) {
+ $errors = $e->validation->errors();
+ $this->assert_same("no_trailing_period", $errors["name"]);
+ }
+ // Should be corrected on save.
+ $item->save();
+ $this->assert_equal(".no_trailing_period.allowed", $item->name);
+ // Should be corrected on update.
+ $item->name = ".no_trailing_period.allowed.";
+ $item->save();
+ $this->assert_equal(".no_trailing_period.allowed", $item->name);
}
public function move_album_test() {
@@ -362,6 +475,7 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$response = item::root()->as_restful_array();
$this->assert_true($response["can_edit"]);
+ access::deny(identity::everybody(), "edit", item::root());
identity::set_active_user(identity::guest());
$response = item::root()->as_restful_array();
$this->assert_false($response["can_edit"]);
@@ -371,6 +485,7 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$response = item::root()->as_restful_array();
$this->assert_true($response["can_add"]);
+ access::deny(identity::everybody(), "add", item::root());
identity::set_active_user(identity::guest());
$response = item::root()->as_restful_array();
$this->assert_false($response["can_add"]);
diff --git a/modules/gallery/tests/Legal_File_Helper_Test.php b/modules/gallery/tests/Legal_File_Helper_Test.php
index 7ed5214b..aab41c41 100644
--- a/modules/gallery/tests/Legal_File_Helper_Test.php
+++ b/modules/gallery/tests/Legal_File_Helper_Test.php
@@ -37,7 +37,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case {
$this->assert_equal(null, legal_file::get_movie_types_by_extension("php.flv")); // invalid w/ .
// No extension returns full array
- $this->assert_equal(3, count(legal_file::get_movie_types_by_extension()));
+ $this->assert_equal(5, count(legal_file::get_movie_types_by_extension()));
}
public function get_types_by_extension_test() {
@@ -47,7 +47,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case {
$this->assert_equal(null, legal_file::get_types_by_extension("php.flv")); // invalid w/ .
// No extension returns full array
- $this->assert_equal(7, count(legal_file::get_types_by_extension()));
+ $this->assert_equal(9, count(legal_file::get_types_by_extension()));
}
public function get_photo_extensions_test() {
@@ -69,7 +69,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case {
$this->assert_equal(false, legal_file::get_movie_extensions("php.jpg")); // invalid w/ .
// No extension returns full array
- $this->assert_equal(3, count(legal_file::get_movie_extensions()));
+ $this->assert_equal(5, count(legal_file::get_movie_extensions()));
}
public function get_extensions_test() {
@@ -79,12 +79,12 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case {
$this->assert_equal(false, legal_file::get_extensions("php.jpg")); // invalid w/ .
// No extension returns full array
- $this->assert_equal(7, count(legal_file::get_extensions()));
+ $this->assert_equal(9, count(legal_file::get_extensions()));
}
public function get_filters_test() {
- // All 7 extensions both uppercase and lowercase
- $this->assert_equal(14, count(legal_file::get_filters()));
+ // All 9 extensions both uppercase and lowercase
+ $this->assert_equal(18, count(legal_file::get_filters()));
}
public function get_photo_types_test() {
@@ -94,7 +94,7 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case {
public function get_movie_types_test() {
// Note that this is one *more* than movie extensions since video/flv is added.
- $this->assert_equal(4, count(legal_file::get_movie_types()));
+ $this->assert_equal(6, count(legal_file::get_movie_types()));
}
public function change_extension_test() {
@@ -194,4 +194,22 @@ class Legal_File_Helper_Test extends Gallery_Unit_Test_Case {
}
}
}
+
+ public function sanitize_dirname_with_no_rename_test() {
+ $this->assert_equal("foo", legal_file::sanitize_dirname("foo"));
+ $this->assert_equal("foo.bar", legal_file::sanitize_dirname("foo.bar"));
+ $this->assert_equal(".foo.bar...baz", legal_file::sanitize_dirname(".foo.bar...baz"));
+ $this->assert_equal("foo bar spaces", legal_file::sanitize_dirname("foo bar spaces"));
+ $this->assert_equal("j'écris@un#nom_bizarre(mais quand_même_ça_passe \$ÇÀ@€",
+ legal_file::sanitize_dirname("j'écris@un#nom_bizarre(mais quand_même_ça_passe \$ÇÀ@€"));
+ }
+
+ public function sanitize_filename_with_corrections_test() {
+ $this->assert_equal("foo_bar", legal_file::sanitize_dirname("/foo/bar/"));
+ $this->assert_equal("foo_bar", legal_file::sanitize_dirname("\\foo\\bar\\"));
+ $this->assert_equal(".foo..bar", legal_file::sanitize_dirname(".foo..bar."));
+ $this->assert_equal("foo_bar", legal_file::sanitize_dirname("_foo__bar_"));
+ $this->assert_equal("album", legal_file::sanitize_dirname("_"));
+ $this->assert_equal("album", legal_file::sanitize_dirname(null));
+ }
} \ No newline at end of file
diff --git a/modules/gallery/tests/Movie_Helper_Test.php b/modules/gallery/tests/Movie_Helper_Test.php
index 03fa2da9..9107827a 100644
--- a/modules/gallery/tests/Movie_Helper_Test.php
+++ b/modules/gallery/tests/Movie_Helper_Test.php
@@ -71,6 +71,7 @@ class Movie_Helper_Test extends Gallery_Unit_Test_Case {
} catch (Exception $e) {
// pass
}
+ unlink(TMPPATH . "test_flv_with_no_extension");
}
public function get_file_metadata_with_illegal_extension_test() {
@@ -91,6 +92,7 @@ class Movie_Helper_Test extends Gallery_Unit_Test_Case {
} catch (Exception $e) {
// pass
}
+ unlink(TMPPATH . "test_flv_with_php_extension.php");
}
public function get_file_metadata_with_valid_extension_but_illegal_file_contents_test() {
@@ -101,5 +103,6 @@ class Movie_Helper_Test extends Gallery_Unit_Test_Case {
// therefore will never be executed.
$this->assert_equal(array(0, 0, "video/x-flv", "flv", 0),
movie::get_file_metadata(TMPPATH . "test_php_with_flv_extension.flv"));
+ unlink(TMPPATH . "test_php_with_flv_extension.flv");
}
}
diff --git a/modules/gallery/tests/Photo_Helper_Test.php b/modules/gallery/tests/Photo_Helper_Test.php
index 79b5ccfd..7ba8324f 100644
--- a/modules/gallery/tests/Photo_Helper_Test.php
+++ b/modules/gallery/tests/Photo_Helper_Test.php
@@ -37,6 +37,7 @@ class Photo_Helper_Test extends Gallery_Unit_Test_Case {
copy(MODPATH . "gallery/tests/test.jpg", TMPPATH . "test_jpg_with_no_extension");
$this->assert_equal(array(1024, 768, "image/jpeg", "jpg"),
photo::get_file_metadata(TMPPATH . "test_jpg_with_no_extension"));
+ unlink(TMPPATH . "test_jpg_with_no_extension");
}
public function get_file_metadata_with_illegal_extension_test() {
@@ -56,6 +57,7 @@ class Photo_Helper_Test extends Gallery_Unit_Test_Case {
copy(MODPATH . "gallery/tests/test.jpg", TMPPATH . "test_jpg_with_php_extension.php");
$this->assert_equal(array(1024, 768, "image/jpeg", "jpg"),
photo::get_file_metadata(TMPPATH . "test_jpg_with_php_extension.php"));
+ unlink(TMPPATH . "test_jpg_with_php_extension.php");
}
public function get_file_metadata_with_valid_extension_but_illegal_file_contents_test() {
@@ -66,5 +68,6 @@ class Photo_Helper_Test extends Gallery_Unit_Test_Case {
} catch (Exception $e) {
// pass
}
+ unlink(TMPPATH . "test_php_with_jpg_extension.jpg");
}
}
diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php
index 946410d4..dab7d7df 100644
--- a/modules/gallery/tests/SafeString_Test.php
+++ b/modules/gallery/tests/SafeString_Test.php
@@ -91,7 +91,7 @@ class SafeString_Test extends Gallery_Unit_Test_Case {
public function purify_test() {
$safe_string = SafeString::purify("hello <p >world</p>");
- $expected = method_exists("purifier", "purify")
+ $expected = (class_exists("purifier") && method_exists("purifier", "purify"))
? "hello <p>world</p>"
: "hello &lt;p &gt;world&lt;/p&gt;";
$this->assert_equal($expected, $safe_string);
@@ -100,7 +100,7 @@ class SafeString_Test extends Gallery_Unit_Test_Case {
public function purify_twice_test() {
$safe_string = SafeString::purify("hello <p >world</p>");
$safe_string_2 = SafeString::purify($safe_string);
- $expected = method_exists("purifier", "purify")
+ $expected = (class_exists("purifier") && method_exists("purifier", "purify"))
? "hello <p>world</p>"
: "hello &lt;p &gt;world&lt;/p&gt;";
$this->assert_equal($expected, $safe_string_2);
diff --git a/modules/gallery/tests/controller_auth_data.txt b/modules/gallery/tests/controller_auth_data.txt
index 9473f9f6..4cd9f047 100644
--- a/modules/gallery/tests/controller_auth_data.txt
+++ b/modules/gallery/tests/controller_auth_data.txt
@@ -1,6 +1,5 @@
modules/comment/controllers/admin_manage_comments.php queue DIRTY_CSRF
modules/comment/helpers/comment_rss.php feed DIRTY_AUTH
-modules/digibug/controllers/digibug.php print_proxy DIRTY_CSRF|DIRTY_AUTH
modules/g2_import/controllers/admin_g2_import.php autocomplete DIRTY_CSRF
modules/g2_import/controllers/g2.php map DIRTY_CSRF
modules/gallery/controllers/admin.php __call DIRTY_AUTH
diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt
index 51347f86..2152858a 100644
--- a/modules/gallery/tests/xss_data.txt
+++ b/modules/gallery/tests/xss_data.txt
@@ -39,12 +39,10 @@ modules/comment/views/comments.html.php 31 DIRTY_ATTR $com
modules/comment/views/user_profile_comments.html.php 5 DIRTY_ATTR $comment->id
modules/comment/views/user_profile_comments.html.php 10 DIRTY_JS $comment->item()->url()
modules/comment/views/user_profile_comments.html.php 11 DIRTY $comment->item()->thumb_img(array(),50)
-modules/digibug/views/digibug_form.html.php 4 DIRTY form::open("http://www.digibug.com/dapi/order.php")
-modules/digibug/views/digibug_form.html.php 6 DIRTY form::hidden($key,$value)
modules/exif/views/exif_dialog.html.php 14 DIRTY $details[$i]["caption"]
modules/exif/views/exif_dialog.html.php 21 DIRTY $details[$i]["caption"]
-modules/g2_import/views/admin_g2_import.html.php 7 DIRTY_JS url::site("__ARGS__")
-modules/g2_import/views/admin_g2_import.html.php 52 DIRTY $form
+modules/g2_import/views/admin_g2_import.html.php 5 DIRTY_JS url::site("__ARGS__")
+modules/g2_import/views/admin_g2_import.html.php 47 DIRTY $form
modules/gallery/views/admin_advanced_settings.html.php 21 DIRTY_ATTR text::alternate("g-odd","g-even")
modules/gallery/views/admin_block_log_entries.html.php 4 DIRTY_ATTR log::severity_class($entry->severity)
modules/gallery/views/admin_block_log_entries.html.php 8 DIRTY_JS user_profile::url($entry->user->id)
@@ -58,7 +56,8 @@ modules/gallery/views/admin_block_photo_stream.html.php 5 DIRTY_JS $photo
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
-modules/gallery/views/admin_dashboard.html.php 35 DIRTY $blocks
+modules/gallery/views/admin_dashboard.html.php 37 DIRTY $obsolete_modules_message
+modules/gallery/views/admin_dashboard.html.php 42 DIRTY $blocks
modules/gallery/views/admin_graphics.html.php 25 DIRTY newView("admin_graphics_none.html")
modules/gallery/views/admin_graphics.html.php 27 DIRTY newView("admin_graphics_$active.html",array("tk"=>$tk->$active,"is_active"=>true))
modules/gallery/views/admin_graphics.html.php 34 DIRTY newView("admin_graphics_$id.html",array("tk"=>$tk->$id,"is_active"=>false))
@@ -98,19 +97,21 @@ modules/gallery/views/admin_maintenance.html.php 181 DIRTY $task-
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 75 DIRTY $task->name
-modules/gallery/views/admin_modules.html.php 51 DIRTY access::csrf_form_field()
-modules/gallery/views/admin_modules.html.php 61 DIRTY_ATTR text::alternate("g-odd","g-even")
-modules/gallery/views/admin_modules.html.php 64 DIRTY form::checkbox($data,'1',module::is_active($module_name))
-modules/gallery/views/admin_modules.html.php 66 DIRTY $module_info->version
-modules/gallery/views/admin_modules.html.php 74 DIRTY_JS $module_info->author_url
-modules/gallery/views/admin_modules.html.php 81 DIRTY_ATTR $module_info->author_name
-modules/gallery/views/admin_modules.html.php 85 DIRTY $module_info->author_name
-modules/gallery/views/admin_modules.html.php 93 DIRTY_JS $module_info->info_url
-modules/gallery/views/admin_modules.html.php 106 DIRTY_JS $module_info->discuss_url
+modules/gallery/views/admin_modules.html.php 51 DIRTY $obsolete_modules_message
+modules/gallery/views/admin_modules.html.php 57 DIRTY access::csrf_form_field()
+modules/gallery/views/admin_modules.html.php 67 DIRTY_ATTR text::alternate("g-odd","g-even")
+modules/gallery/views/admin_modules.html.php 70 DIRTY form::checkbox($data,'1',module::is_active($module_name))
+modules/gallery/views/admin_modules.html.php 72 DIRTY $module_info->version
+modules/gallery/views/admin_modules.html.php 80 DIRTY_JS $module_info->author_url
+modules/gallery/views/admin_modules.html.php 87 DIRTY_ATTR $module_info->author_name
+modules/gallery/views/admin_modules.html.php 91 DIRTY $module_info->author_name
+modules/gallery/views/admin_modules.html.php 99 DIRTY_JS $module_info->info_url
+modules/gallery/views/admin_modules.html.php 112 DIRTY_JS $module_info->discuss_url
modules/gallery/views/admin_modules_confirm.html.php 11 DIRTY_ATTR $css_class
modules/gallery/views/admin_modules_confirm.html.php 11 DIRTY $message
modules/gallery/views/admin_modules_confirm.html.php 16 DIRTY access::csrf_form_field()
modules/gallery/views/admin_modules_confirm.html.php 18 DIRTY form::hidden($module,1)
+modules/gallery/views/admin_movies.html.php 43 DIRTY $form
modules/gallery/views/admin_sidebar.html.php 50 DIRTY $available
modules/gallery/views/admin_sidebar.html.php 58 DIRTY $active
modules/gallery/views/admin_sidebar_blocks.html.php 4 DIRTY_ATTR $ref
@@ -215,20 +216,20 @@ modules/gallery/views/menu.html.php 18 DIRTY $eleme
modules/gallery/views/menu_ajax_link.html.php 3 DIRTY $menu->css_id?"id='{$menu->css_id}'":""
modules/gallery/views/menu_ajax_link.html.php 4 DIRTY_ATTR $menu->css_class
modules/gallery/views/menu_ajax_link.html.php 5 DIRTY_JS $menu->url
-modules/gallery/views/menu_ajax_link.html.php 7 DIRTY $menu->ajax_handler
+modules/gallery/views/menu_ajax_link.html.php 7 DIRTY_ATTR $menu->ajax_handler
modules/gallery/views/menu_dialog.html.php 3 DIRTY $menu->css_id?"id='{$menu->css_id}'":""
modules/gallery/views/menu_dialog.html.php 4 DIRTY_ATTR $menu->css_class
modules/gallery/views/menu_dialog.html.php 5 DIRTY_JS $menu->url
modules/gallery/views/menu_link.html.php 3 DIRTY $menu->css_id?"id='{$menu->css_id}'":""
modules/gallery/views/menu_link.html.php 4 DIRTY_ATTR $menu->css_class
modules/gallery/views/menu_link.html.php 5 DIRTY_JS $menu->url
-modules/gallery/views/movieplayer.html.php 2 DIRTY html::anchor($url,"",$attrs)
-modules/gallery/views/movieplayer.html.php 4 DIRTY_JS $attrs["id"]
-modules/gallery/views/movieplayer.html.php 5 DIRTY_JS $max_size
-modules/gallery/views/movieplayer.html.php 23 DIRTY_JS url::abs_file("lib/flowplayer.swf")
-modules/gallery/views/movieplayer.html.php 30 DIRTY_JS url::abs_file("lib/flowplayer.pseudostreaming-byterange.swf")
-modules/gallery/views/movieplayer.html.php 48 DIRTY_JS $width
-modules/gallery/views/movieplayer.html.php 48 DIRTY_JS $height
+modules/gallery/views/movieplayer.html.php 2 DIRTY html::attributes($div_attrs)
+modules/gallery/views/movieplayer.html.php 3 DIRTY html::attributes($video_attrs)
+modules/gallery/views/movieplayer.html.php 4 DIRTY html::attributes($source_attrs)
+modules/gallery/views/movieplayer.html.php 8 DIRTY_JS $div_attrs["id"]
+modules/gallery/views/movieplayer.html.php 10 DIRTY_JS $width
+modules/gallery/views/movieplayer.html.php 11 DIRTY_JS $height
+modules/gallery/views/movieplayer.html.php 14 DIRTY_JS url::abs_file("lib/mediaelementjs/")
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 43 DIRTY_ATTR $parent->id
@@ -265,14 +266,15 @@ modules/gallery/views/quick_delete_confirm.html.php 11 DIRTY $form
modules/gallery/views/reauthenticate.html.php 9 DIRTY $form
modules/gallery/views/upgrade_checker_block.html.php 19 DIRTY $new_version
modules/gallery/views/upgrader.html.php 76 DIRTY_ATTR $done?"muted":""
-modules/gallery/views/upgrader.html.php 94 DIRTY_ATTR $done?"muted":""
-modules/gallery/views/upgrader.html.php 102 DIRTY_ATTR $module->version==$module->code_version?"current":"upgradeable"
-modules/gallery/views/upgrader.html.php 102 DIRTY_ATTR in_array($id,$failed)?"failed":""
-modules/gallery/views/upgrader.html.php 103 DIRTY_ATTR $id
-modules/gallery/views/upgrader.html.php 107 DIRTY $module->version
-modules/gallery/views/upgrader.html.php 110 DIRTY $module->code_version
-modules/gallery/views/upgrader.html.php 120 DIRTY_ATTR $done?"muted":""
-modules/gallery/views/upgrader.html.php 123 DIRTY_ATTR $done?"muted":""
+modules/gallery/views/upgrader.html.php 97 DIRTY $obsolete_modules_message
+modules/gallery/views/upgrader.html.php 103 DIRTY_ATTR $done?"muted":""
+modules/gallery/views/upgrader.html.php 111 DIRTY_ATTR $module->version==$module->code_version?"current":"upgradeable"
+modules/gallery/views/upgrader.html.php 111 DIRTY_ATTR in_array($id,$failed)?"failed":""
+modules/gallery/views/upgrader.html.php 112 DIRTY_ATTR $id
+modules/gallery/views/upgrader.html.php 116 DIRTY $module->version
+modules/gallery/views/upgrader.html.php 119 DIRTY $module->code_version
+modules/gallery/views/upgrader.html.php 129 DIRTY_ATTR $done?"muted":""
+modules/gallery/views/upgrader.html.php 132 DIRTY_ATTR $done?"muted":""
modules/gallery/views/user_languages_block.html.php 2 DIRTY form::dropdown("g-select-session-locale",$installed_locales,$selected)
modules/gallery/views/user_profile.html.php 34 DIRTY_ATTR $user->avatar_url(40,$theme->url(,true))
modules/gallery/views/user_profile.html.php 43 DIRTY $info->view
@@ -342,16 +344,15 @@ modules/rss/views/feed.mrss.php 67 DIRTY_ATTR $ite
modules/rss/views/feed.mrss.php 68 DIRTY_ATTR $item->height
modules/rss/views/feed.mrss.php 69 DIRTY_ATTR $item->width
modules/rss/views/rss_block.html.php 6 DIRTY_JS rss::url($url)
-modules/search/views/search.html.php 39 DIRTY_ATTR $item_class
-modules/search/views/search.html.php 40 DIRTY_JS $item->url()
-modules/search/views/search.html.php 41 DIRTY $item->thumb_img(array("class"=>"g-thumbnail"))
modules/search/views/search.html.php 43 DIRTY_ATTR $item_class
-modules/search/views/search.html.php 53 DIRTY $theme->paginator()
-modules/search/views/search_link.html.php 14 DIRTY_ATTR $item->id
-modules/search/views/search_link.html.php 16 DIRTY_ATTR $item->parent_id
-modules/server_add/views/admin_server_add.html.php 8 DIRTY_JS url::site("__ARGS__")
-modules/server_add/views/admin_server_add.html.php 19 DIRTY $form
-modules/server_add/views/admin_server_add.html.php 30 DIRTY_ATTR $id
+modules/search/views/search.html.php 44 DIRTY_JS $item->url()
+modules/search/views/search.html.php 45 DIRTY $item->thumb_img(array("class"=>"g-thumbnail"))
+modules/search/views/search.html.php 47 DIRTY_ATTR $item_class
+modules/search/views/search.html.php 57 DIRTY $theme->paginator()
+modules/search/views/search_link.html.php 15 DIRTY_ATTR $album_id
+modules/server_add/views/admin_server_add.html.php 6 DIRTY_JS url::site("__ARGS__")
+modules/server_add/views/admin_server_add.html.php 14 DIRTY $form
+modules/server_add/views/admin_server_add.html.php 25 DIRTY_ATTR $id
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.html.php 21 DIRTY_ATTR is_dir($file)?"g-directory":"g-file"
modules/server_add/views/server_add_tree_dialog.html.php 3 DIRTY_JS url::site("server_add/children?path=__PATH__")
@@ -359,8 +360,8 @@ modules/server_add/views/server_add_tree_dialog.html.php 4 DIRTY_JS url::s
modules/server_add/views/server_add_tree_dialog.html.php 21 DIRTY $tree
modules/tag/views/admin_tags.html.php 45 DIRTY_ATTR $tag->id
modules/tag/views/admin_tags.html.php 46 DIRTY $tag->count
-modules/tag/views/tag_block.html.php 28 DIRTY $cloud
-modules/tag/views/tag_block.html.php 30 DIRTY $form
+modules/tag/views/tag_block.html.php 26 DIRTY $cloud
+modules/tag/views/tag_block.html.php 28 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/tag/views/tag_cloud.html.php 6 DIRTY_JS $tag->url()
@@ -387,19 +388,19 @@ modules/watermark/views/admin_watermarks.html.php 20 DIRTY_ATTR $url
themes/admin_wind/views/admin.html.php 4 DIRTY $theme->html_attributes()
themes/admin_wind/views/admin.html.php 34 DIRTY $theme->admin_head()
themes/admin_wind/views/admin.html.php 46 DIRTY_JS $theme->url()
-themes/admin_wind/views/admin.html.php 51 DIRTY $theme->get_combined("css")
-themes/admin_wind/views/admin.html.php 54 DIRTY $theme->get_combined("script")
-themes/admin_wind/views/admin.html.php 58 DIRTY $theme->admin_page_top()
-themes/admin_wind/views/admin.html.php 66 DIRTY $theme->admin_header_top()
-themes/admin_wind/views/admin.html.php 67 DIRTY_JS item::root()->url()
-themes/admin_wind/views/admin.html.php 70 DIRTY $theme->user_menu()
-themes/admin_wind/views/admin.html.php 73 DIRTY $theme->admin_menu()
-themes/admin_wind/views/admin.html.php 76 DIRTY $theme->admin_header_bottom()
-themes/admin_wind/views/admin.html.php 83 DIRTY $content
-themes/admin_wind/views/admin.html.php 89 DIRTY $sidebar
-themes/admin_wind/views/admin.html.php 94 DIRTY $theme->admin_footer()
-themes/admin_wind/views/admin.html.php 97 DIRTY $theme->admin_credits()
-themes/admin_wind/views/admin.html.php 102 DIRTY $theme->admin_page_bottom()
+themes/admin_wind/views/admin.html.php 50 DIRTY $theme->get_combined("css")
+themes/admin_wind/views/admin.html.php 51 DIRTY $theme->get_combined("script")
+themes/admin_wind/views/admin.html.php 55 DIRTY $theme->admin_page_top()
+themes/admin_wind/views/admin.html.php 63 DIRTY $theme->admin_header_top()
+themes/admin_wind/views/admin.html.php 64 DIRTY_JS item::root()->url()
+themes/admin_wind/views/admin.html.php 67 DIRTY $theme->user_menu()
+themes/admin_wind/views/admin.html.php 70 DIRTY $theme->admin_menu()
+themes/admin_wind/views/admin.html.php 73 DIRTY $theme->admin_header_bottom()
+themes/admin_wind/views/admin.html.php 80 DIRTY $content
+themes/admin_wind/views/admin.html.php 86 DIRTY $sidebar
+themes/admin_wind/views/admin.html.php 91 DIRTY $theme->admin_footer()
+themes/admin_wind/views/admin.html.php 94 DIRTY $theme->admin_credits()
+themes/admin_wind/views/admin.html.php 99 DIRTY $theme->admin_page_bottom()
themes/admin_wind/views/block.html.php 3 DIRTY_ATTR $anchor
themes/admin_wind/views/block.html.php 5 DIRTY $id
themes/admin_wind/views/block.html.php 5 DIRTY_ATTR $css_id
@@ -434,18 +435,18 @@ themes/wind/views/page.html.php 10 DIRTY $page_
themes/wind/views/page.html.php 32 DIRTY $new_width
themes/wind/views/page.html.php 33 DIRTY $new_height
themes/wind/views/page.html.php 34 DIRTY $thumb_proportion
-themes/wind/views/page.html.php 74 DIRTY_JS $theme->url()
-themes/wind/views/page.html.php 79 DIRTY $theme->get_combined("css")
-themes/wind/views/page.html.php 82 DIRTY $theme->get_combined("script")
-themes/wind/views/page.html.php 92 DIRTY $header_text
-themes/wind/views/page.html.php 94 DIRTY_JS item::root()->url()
-themes/wind/views/page.html.php 98 DIRTY $theme->user_menu()
-themes/wind/views/page.html.php 113 DIRTY_ATTR $breadcrumb->last?"g-active":""
-themes/wind/views/page.html.php 114 DIRTY_ATTR $breadcrumb->first?"g-first":""
-themes/wind/views/page.html.php 115 DIRTY_JS $breadcrumb->url
-themes/wind/views/page.html.php 128 DIRTY $content
-themes/wind/views/page.html.php 134 DIRTY newView("sidebar.html")
-themes/wind/views/page.html.php 141 DIRTY $footer_text
+themes/wind/views/page.html.php 68 DIRTY_JS $theme->url()
+themes/wind/views/page.html.php 72 DIRTY $theme->get_combined("css")
+themes/wind/views/page.html.php 73 DIRTY $theme->get_combined("script")
+themes/wind/views/page.html.php 83 DIRTY $header_text
+themes/wind/views/page.html.php 85 DIRTY_JS item::root()->url()
+themes/wind/views/page.html.php 89 DIRTY $theme->user_menu()
+themes/wind/views/page.html.php 104 DIRTY_ATTR $breadcrumb->last?"g-active":""
+themes/wind/views/page.html.php 105 DIRTY_ATTR $breadcrumb->first?"g-first":""
+themes/wind/views/page.html.php 106 DIRTY_JS $breadcrumb->url
+themes/wind/views/page.html.php 119 DIRTY $content
+themes/wind/views/page.html.php 125 DIRTY newView("sidebar.html")
+themes/wind/views/page.html.php 132 DIRTY $footer_text
themes/wind/views/paginator.html.php 33 DIRTY_JS $first_page_url
themes/wind/views/paginator.html.php 42 DIRTY_JS $previous_page_url
themes/wind/views/paginator.html.php 70 DIRTY_JS $next_page_url
diff --git a/modules/gallery/views/admin_advanced_settings.html.php b/modules/gallery/views/admin_advanced_settings.html.php
index 6745f0df..f4f0c81d 100644
--- a/modules/gallery/views/admin_advanced_settings.html.php
+++ b/modules/gallery/views/admin_advanced_settings.html.php
@@ -39,8 +39,8 @@
<script>
$(document).ready(function() {
- $("#g-admin-advanced-settings-filter").keyup(function() {
- var filter = $(this).attr("value");
+ $("#g-admin-advanced-settings-filter").on("input keyup", function() {
+ var filter = $(this).val();
if (filter) {
$("tr.setting-row").fadeOut("fast");
$("tr.setting-row").each(function() {
diff --git a/modules/gallery/views/admin_dashboard.html.php b/modules/gallery/views/admin_dashboard.html.php
index f391547e..cf90ef28 100644
--- a/modules/gallery/views/admin_dashboard.html.php
+++ b/modules/gallery/views/admin_dashboard.html.php
@@ -31,6 +31,13 @@
});
});
</script>
+<div>
+ <? if ($obsolete_modules_message): ?>
+ <p class="g-warning">
+ <?= $obsolete_modules_message ?>
+ </p>
+ <? endif ?>
+</div>
<div id="g-admin-dashboard">
<?= $blocks ?>
</div>
diff --git a/modules/gallery/views/admin_modules.html.php b/modules/gallery/views/admin_modules.html.php
index 5a7f7b6c..96576ae4 100644
--- a/modules/gallery/views/admin_modules.html.php
+++ b/modules/gallery/views/admin_modules.html.php
@@ -46,6 +46,12 @@
<?= t("Power up your Gallery by <a href=\"%url\">adding more modules</a>! Each module provides new cool features.", array("url" => "http://codex.galleryproject.org/Category:Gallery_3:Modules")) ?>
</p>
+ <? if ($obsolete_modules_message): ?>
+ <p class="g-warning">
+ <?= $obsolete_modules_message ?>
+ </p>
+ <? endif ?>
+
<div class="g-block-content">
<form id="g-module-update-form" method="post" action="<?= url::site("admin/modules/confirm") ?>">
<?= access::csrf_form_field() ?>
diff --git a/modules/gallery/views/admin_movies.html.php b/modules/gallery/views/admin_movies.html.php
new file mode 100644
index 00000000..abf8fb29
--- /dev/null
+++ b/modules/gallery/views/admin_movies.html.php
@@ -0,0 +1,44 @@
+<?php defined("SYSPATH") or die("No direct script access.") ?>
+<div id="g-movies-admin" class="g-block ui-helper-clearfix">
+ <h1> <?= t("Movies settings") ?> </h1>
+ <p>
+ <?= t("Gallery comes with everything it needs to upload and play movies.") ?>
+ <?= t("However, it needs the FFmpeg toolkit to extract thumbnails and size information from them.") ?>
+ </p>
+ <p>
+ <?= t("Although popular, FFmpeg is not installed on all Linux systems.") ?>
+ <?= t("To use FFmpeg without fully installing it, download a pre-compiled, <b>static build</b> of FFmpeg from one of the links <a href=\"%url\">here</a>.", array("url" => "http://ffmpeg.org/download.html")) ?>
+ <?= t("Then, put the \"ffmpeg\" file in Gallery's \"bin\" directory (e.g. \"/gallery3/bin\"), where Gallery will auto-detect it.") ?>
+ </p>
+ <p>
+ <?= t("Movies will work without FFmpeg, but their thumbnails will be placeholders.") ?>
+ </p>
+ <p>
+ <?= t("Can't get FFmpeg configured on your system? <a href=\"%url\">We can help!</a>",
+ array("url" => "http://codex.galleryproject.org/Gallery3:FAQ#Why_does_it_say_I.27m_missing_ffmpeg.3F")) ?>
+ </p>
+
+ <div class="g-available">
+ <h2> <?= t("Current configuration") ?> </h2>
+ <div id="g-ffmpeg" class="g-block">
+ <img class="logo" width="284" height="70" src="<?= url::file("modules/gallery/images/ffmpeg.png") ?>" alt="<? t("Visit the FFmpeg project site") ?>" />
+ <p>
+ <?= t("FFmpeg is a cross-platform standalone audio/video program.") ?><br/>
+ <?= t("Please refer to the <a href=\"%url\">FFmpeg website</a> for more information.", array("url" => "http://ffmpeg.org")) ?>
+ </p>
+ <div class="g-module-status g-info">
+ <? if ($ffmpeg_dir): ?>
+ <? if ($ffmpeg_version): ?>
+ <p><?= t("FFmpeg version %version was found in %dir", array("version" => $ffmpeg_version, "dir" => $ffmpeg_dir)) ?></p>
+ <? else: ?>
+ <p><?= t("FFmpeg (of unknown version) was found in %dir", array("dir" => $ffmpeg_dir)) ?></p>
+ <? endif ?>
+ <? else: ?>
+ <p><?= t("We could not locate FFmpeg on your system.") ?></p>
+ <? endif ?>
+ </div>
+ </div>
+ </div>
+
+ <?= $form ?>
+</div>
diff --git a/modules/gallery/views/form_uploadify.html.php b/modules/gallery/views/form_uploadify.html.php
index 4426514a..c13e3418 100644
--- a/modules/gallery/views/form_uploadify.html.php
+++ b/modules/gallery/views/form_uploadify.html.php
@@ -131,7 +131,7 @@
<? if (identity::active_user()->admin && !$movies_allowed): ?>
<p class="g-warning">
- <?= t("Can't find <i>ffmpeg</i> on your system. Movie uploading disabled. <a href=\"%help_url\">Help!</a>", array("help_url" => "http://codex.galleryproject.org/Gallery3:FAQ#Why_does_it_say_I.27m_missing_ffmpeg.3F")) ?>
+ <?= t("Movie uploading is disabled on your system. <a href=\"%help_url\">Help!</a>", array("help_url" => url::site("admin/movies"))) ?>
</p>
<? endif ?>
</div>
diff --git a/modules/gallery/views/in_place_edit.html.php b/modules/gallery/views/in_place_edit.html.php
index 2d6cbe90..c2515a03 100644
--- a/modules/gallery/views/in_place_edit.html.php
+++ b/modules/gallery/views/in_place_edit.html.php
@@ -8,7 +8,7 @@
<li>
<?= form::submit(array("class" => "submit ui-state-default"), t("Save")) ?>
</li>
- <li><a href="#" class="g-cancel"><?= t("Cancel") ?></a></li>
+ <li><button class="g-cancel ui-state-default ui-corner-all"><?= t("Cancel") ?></button></li>
<? if (!empty($errors["input"])): ?>
<li>
<p id="g-in-place-edit-message" class="g-error"><?= $errors["input"] ?></p>
diff --git a/modules/gallery/views/menu_ajax_link.html.php b/modules/gallery/views/menu_ajax_link.html.php
index 06cd6f92..66df84c9 100644
--- a/modules/gallery/views/menu_ajax_link.html.php
+++ b/modules/gallery/views/menu_ajax_link.html.php
@@ -4,7 +4,7 @@
class="g-ajax-link <?= $menu->css_class ?>"
href="<?= $menu->url ?>"
title="<?= $menu->label->for_html_attr() ?>"
- ajax_handler="<?= $menu->ajax_handler ?>">
+ data-ajax-handler="<?= $menu->ajax_handler ?>">
<?= $menu->label->for_html() ?>
</a>
</li>
diff --git a/modules/gallery/views/movieplayer.html.php b/modules/gallery/views/movieplayer.html.php
index edb5184c..f78cc91a 100644
--- a/modules/gallery/views/movieplayer.html.php
+++ b/modules/gallery/views/movieplayer.html.php
@@ -1,49 +1,17 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
-<?= html::anchor($url, "", $attrs) ?>
+<div <?= html::attributes($div_attrs) ?>>
+ <video <?= html::attributes($video_attrs) ?>>
+ <source <?= html::attributes($source_attrs) ?>>
+ </video>
+</div>
<script type="text/javascript">
- var id = "<?= $attrs["id"] ?>";
- var max_size = <?= $max_size ?>;
- // set the size of the movie html anchor, taking into account max_size and height of control bar
- function set_movie_size(width, height) {
- if((width > max_size) || (height > max_size)) {
- if (width > height) {
- height = Math.ceil(height * max_size / width);
- width = max_size;
- } else {
- width = Math.ceil(width * max_size / height);
- height = max_size;
- }
- }
- height += flowplayer(id).getConfig().plugins.controls.height;
- $("#" + id).css({width: width, height: height});
- };
- // setup flowplayer
- flowplayer(id,
+ $("#<?= $div_attrs["id"] ?> video").mediaelementplayer(
$.extend(true, {
- "src": "<?= url::abs_file("lib/flowplayer.swf") ?>",
- "wmode": "transparent",
- "provider": "pseudostreaming"
- }, <?= json_encode($fp_params) ?>),
- $.extend(true, {
- "plugins": {
- "pseudostreaming": {
- "url": "<?= url::abs_file("lib/flowplayer.pseudostreaming-byterange.swf") ?>"
- },
- "controls": {
- "autoHide": "always",
- "hideDelay": 2000,
- "height": 24
- }
- },
- "clip": {
- "scaling": "fit",
- "onMetaData": function(clip) {
- // set movie size a second time using actual size from metadata
- set_movie_size(parseInt(clip.metaData.width), parseInt(clip.metaData.height));
- }
- }
- }, <?= json_encode($fp_config) ?>)
- ).ipad();
- // set movie size using width and height passed from movie_img function
- $("document").ready(set_movie_size(<?= $width ?>, <?= $height ?>));
+ defaultVideoWidth: <?= $width ?>,
+ defaultVideoHeight: <?= $height ?>,
+ startVolume: 1.0,
+ features: ["playpause", "progress", "current", "duration", "volume", "fullscreen"],
+ pluginPath: "<?= url::abs_file("lib/mediaelementjs/") ?>"
+ }, <?= json_encode($player_options) ?>)
+ );
</script>
diff --git a/modules/gallery/views/upgrader.html.php b/modules/gallery/views/upgrader.html.php
index edfaf720..2e485c08 100644
--- a/modules/gallery/views/upgrader.html.php
+++ b/modules/gallery/views/upgrader.html.php
@@ -17,7 +17,7 @@
<a id="dialog_close_link" style="display: none" onclick="$('#dialog').fadeOut(); return false;" href="#" class="close">[x]</a>
<div id="busy" style="display: none">
<h1>
- <img width="16" height="16" src="<?= url::file("themes/wind/images/loading-small.gif") ?>"/>
+ <img width="16" height="16" src="<?= url::file("modules/gallery/images/loading-small.gif") ?>"/>
<?= t("Upgrade in progress!") ?>
</h1>
<p>
@@ -90,6 +90,15 @@
</div>
<? endif ?>
+ <? if ($obsolete_modules_message): ?>
+ <div id="obsolete_modules_message">
+ <p>
+ <span class="failed"><?= t("Warning!") ?></span>
+ <?= $obsolete_modules_message ?>
+ </p>
+ </div>
+ <? endif ?>
+
<table>
<tr class="<?= $done ? "muted" : "" ?>">
<th class="name"> <?= t("Module name") ?> </th>