diff options
author | Nathan Kinkade <nath@nkinka.de> | 2013-03-19 16:41:42 +0000 |
---|---|---|
committer | Nathan Kinkade <nath@nkinka.de> | 2013-03-19 16:41:42 +0000 |
commit | 3908e37d965fa76ea774e76ddf42365a872a5f27 (patch) | |
tree | 457e1a1e465f83855eee96ba287cd91f1623395c /modules/gallery/helpers | |
parent | 711651f727e093cc7357a6bbff6bd992fd6dfd80 (diff) | |
parent | 1eab94f6062b5f54ea5d9db01d968e7195f3de9d (diff) |
Merge branch 'master' of git://github.com/gallery/gallery3
Diffstat (limited to 'modules/gallery/helpers')
-rw-r--r-- | modules/gallery/helpers/album.php | 9 | ||||
-rw-r--r-- | modules/gallery/helpers/block_manager.php | 10 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_event.php | 39 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_installer.php | 32 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_task.php | 6 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_theme.php | 4 | ||||
-rw-r--r-- | modules/gallery/helpers/graphics.php | 6 | ||||
-rw-r--r-- | modules/gallery/helpers/item.php | 81 | ||||
-rw-r--r-- | modules/gallery/helpers/legal_file.php | 32 | ||||
-rw-r--r-- | modules/gallery/helpers/module.php | 72 | ||||
-rw-r--r-- | modules/gallery/helpers/movie.php | 36 | ||||
-rw-r--r-- | modules/gallery/helpers/photo.php | 7 | ||||
-rw-r--r-- | modules/gallery/helpers/system.php | 33 | ||||
-rw-r--r-- | modules/gallery/helpers/task.php | 2 |
14 files changed, 318 insertions, 51 deletions
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; } |