summaryrefslogtreecommitdiff
path: root/modules/gallery/helpers/gallery_task.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gallery/helpers/gallery_task.php')
-rw-r--r--modules/gallery/helpers/gallery_task.php117
1 files changed, 105 insertions, 12 deletions
diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php
index 65a72884..856d2639 100644
--- a/modules/gallery/helpers/gallery_task.php
+++ b/modules/gallery/helpers/gallery_task.php
@@ -1,7 +1,7 @@
<?php defined("SYSPATH") or die("No direct script access.");
/**
* Gallery - a web based photo album viewer and editor
- * Copyright (C) 2000-2012 Bharat Mediratta
+ * 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
@@ -26,11 +26,13 @@ class gallery_task_Core {
const FIX_STATE_RUN_DUPE_SLUGS = 5;
const FIX_STATE_START_DUPE_NAMES = 6;
const FIX_STATE_RUN_DUPE_NAMES = 7;
- const FIX_STATE_START_REBUILD_ITEM_CACHES = 8;
- const FIX_STATE_RUN_REBUILD_ITEM_CACHES = 9;
- const FIX_STATE_START_MISSING_ACCESS_CACHES = 10;
- const FIX_STATE_RUN_MISSING_ACCESS_CACHES = 11;
- const FIX_STATE_DONE = 12;
+ const FIX_STATE_START_DUPE_BASE_NAMES = 8;
+ const FIX_STATE_RUN_DUPE_BASE_NAMES = 9;
+ const FIX_STATE_START_REBUILD_ITEM_CACHES = 10;
+ const FIX_STATE_RUN_REBUILD_ITEM_CACHES = 11;
+ const FIX_STATE_START_MISSING_ACCESS_CACHES = 12;
+ const FIX_STATE_RUN_MISSING_ACCESS_CACHES = 13;
+ const FIX_STATE_DONE = 14;
static function available_tasks() {
$dirty_count = graphics::find_dirty_images_query()->count_records();
@@ -348,8 +350,9 @@ class gallery_task_Core {
// album audit (permissions and bogus album covers): 1 operation for every album
$total += db::build()->where("type", "=", "album")->count_records("items");
- // one operation for each missing slug, name and access cache
- foreach (array("find_dupe_slugs", "find_dupe_names", "find_missing_access_caches") as $func) {
+ // one operation for each dupe slug, dupe name, dupe base name, and missing access cache
+ foreach (array("find_dupe_slugs", "find_dupe_names", "find_dupe_base_names",
+ "find_missing_access_caches") as $func) {
foreach (self::$func() as $row) {
$total++;
}
@@ -489,11 +492,12 @@ class gallery_task_Core {
$task->set("stack", implode(" ", $stack));
$state = self::FIX_STATE_RUN_DUPE_NAMES;
} else {
- $state = self::FIX_STATE_START_ALBUMS;
+ $state = self::FIX_STATE_START_DUPE_BASE_NAMES;
}
break;
case self::FIX_STATE_RUN_DUPE_NAMES:
+ // NOTE: This does *not* attempt to fix the file system!
$stack = explode(" ", $task->get("stack"));
list ($parent_id, $name) = explode(":", array_pop($stack));
@@ -505,9 +509,16 @@ class gallery_task_Core {
->find_all(1, 1);
if ($conflicts->count() && $conflict = $conflicts->current()) {
$task->log("Fixing conflicting name for item id {$conflict->id}");
+ if (!$conflict->is_album() && preg_match("/^(.*)(\.[^\.\/]*?)$/", $conflict->name, $matches)) {
+ $item_base_name = $matches[1];
+ $item_extension = $matches[2]; // includes a leading dot
+ } else {
+ $item_base_name = $conflict->name;
+ $item_extension = "";
+ }
db::build()
->update("items")
- ->set("name", $name . "-" . (string)rand(1000, 9999))
+ ->set("name", $item_base_name . "-" . (string)rand(1000, 9999) . $item_extension)
->where("id", "=", $conflict->id)
->execute();
@@ -522,6 +533,74 @@ class gallery_task_Core {
$completed++;
if (empty($stack)) {
+ $state = self::FIX_STATE_START_DUPE_BASE_NAMES;
+ }
+ break;
+
+ case self::FIX_STATE_START_DUPE_BASE_NAMES:
+ $stack = array();
+ foreach (self::find_dupe_base_names() as $row) {
+ list ($parent_id, $base_name) = explode(":", $row->parent_base_name, 2);
+ $stack[] = join(":", array($parent_id, $base_name));
+ }
+ if ($stack) {
+ $task->set("stack", implode(" ", $stack));
+ $state = self::FIX_STATE_RUN_DUPE_BASE_NAMES;
+ } else {
+ $state = self::FIX_STATE_START_ALBUMS;
+ }
+ break;
+
+ case self::FIX_STATE_RUN_DUPE_BASE_NAMES:
+ // NOTE: This *does* attempt to fix the file system! So, it must go *after* run_dupe_names.
+ $stack = explode(" ", $task->get("stack"));
+ list ($parent_id, $base_name) = explode(":", array_pop($stack));
+ $base_name_escaped = Database::escape_for_like($base_name);
+
+ $fixed = 0;
+ // We want to leave the first one alone and update all conflicts to be random values.
+ $conflicts = ORM::factory("item")
+ ->where("parent_id", "=", $parent_id)
+ ->where("name", "LIKE", "{$base_name_escaped}.%")
+ ->where("type", "<>", "album")
+ ->find_all(1, 1);
+ if ($conflicts->count() && $conflict = $conflicts->current()) {
+ $task->log("Fixing conflicting name for item id {$conflict->id}");
+ if (preg_match("/^(.*)(\.[^\.\/]*?)$/", $conflict->name, $matches)) {
+ $item_base_name = $matches[1]; // unlike $base_name, this always maintains capitalization
+ $item_extension = $matches[2]; // includes a leading dot
+ } else {
+ $item_base_name = $conflict->name;
+ $item_extension = "";
+ }
+ // Unlike conflicts found in run_dupe_names, these items are likely to have an intact
+ // file system. Let's use the item save logic to rebuild the paths and rename the files
+ // if possible.
+ try {
+ $conflict->name = $item_base_name . "-" . (string)rand(1000, 9999) . $item_extension;
+ $conflict->validate();
+ // If we get here, we're safe to proceed with save
+ $conflict->save();
+ } catch (Exception $e) {
+ // Didn't work. Edit database directly without fixing file system.
+ db::build()
+ ->update("items")
+ ->set("name", $item_base_name . "-" . (string)rand(1000, 9999) . $item_extension)
+ ->where("id", "=", $conflict->id)
+ ->execute();
+ }
+
+ // We fixed one conflict, but there might be more so put this parent back on the stack
+ // and try again. We won't consider it completed when we don't fix a conflict. This
+ // guarantees that we won't spend too long fixing one set of conflicts, and that we
+ // won't stop before all are fixed.
+ $stack[] = "$parent_id:$base_name";
+ break;
+ }
+ $task->set("stack", implode(" ", $stack));
+ $completed++;
+
+ if (empty($stack)) {
$state = self::FIX_STATE_START_ALBUMS;
}
break;
@@ -612,7 +691,7 @@ class gallery_task_Core {
break;
case self::FIX_STATE_RUN_MISSING_ACCESS_CACHES:
- $stack = explode(" ", $task->get("stack"));
+ $stack = array_filter(explode(" ", $task->get("stack"))); // filter removes empty/zero ids
if (!empty($stack)) {
$id = array_pop($stack);
$access_cache = ORM::factory("access_cache");
@@ -669,18 +748,32 @@ class gallery_task_Core {
}
static function find_dupe_names() {
+ // looking for photos, movies, and albums
return db::build()
->select_distinct(
array("parent_name" => db::expr("CONCAT(`parent_id`, ':', LOWER(`name`))")))
->select("id")
->select(array("C" => "COUNT(\"*\")"))
->from("items")
- ->where("type", "<>", "album")
->having("C", ">", 1)
->group_by("parent_name")
->execute();
}
+ static function find_dupe_base_names() {
+ // looking for photos or movies, not albums
+ return db::build()
+ ->select_distinct(
+ array("parent_base_name" => db::expr("CONCAT(`parent_id`, ':', LOWER(SUBSTR(`name`, 1, LOCATE('.', `name`) - 1)))")))
+ ->select("id")
+ ->select(array("C" => "COUNT(\"*\")"))
+ ->from("items")
+ ->where("type", "<>", "album")
+ ->having("C", ">", 1)
+ ->group_by("parent_base_name")
+ ->execute();
+ }
+
static function find_empty_item_caches($limit) {
return db::build()
->select("items.id")