diff --git a/.gitignore b/.gitignore
index c47758df..b1d70c05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ thumbs
data
sql.log
shimmie.log
+!lib/images
ext/admin
ext/artists
ext/autocomplete
diff --git a/core/extension.class.php b/core/extension.class.php
index 422edf53..9b514318 100644
--- a/core/extension.class.php
+++ b/core/extension.class.php
@@ -98,6 +98,7 @@ abstract class SimpleExtension implements Extension {
public function receive_event(Event $event) {
$name = get_class($event);
+ // this is rather clever..
$name = "on".str_replace("Event", "", $name);
if(method_exists($this->_child, $name)) {
$this->_child->$name($event);
@@ -133,15 +134,50 @@ abstract class DataHandlerExtension implements Extension {
if(is_null($this->theme)) $this->theme = get_theme_object($this);
if(($event instanceof DataUploadEvent) && $this->supported_ext($event->type) && $this->check_contents($event->tmpname)) {
+
if(!move_upload_to_archive($event)) return;
send_event(new ThumbnailGenerationEvent($event->hash, $event->type));
- $image = $this->create_image_from_data(warehouse_path("images", $event->hash), $event->metadata);
- if(is_null($image)) {
- throw new UploadException("Data handler failed to create image object from data");
+
+ /* Check if we are replacing an image */
+ if (array_key_exists('replace',$event->metadata) && isset($event->metadata['replace']))
+ {
+ /* hax: This seems like such a dirty way to do this.. */
+
+ /* Validate things */
+ $image_id = int_escape($event->metadata['replace']);
+
+ /* Check to make sure the image exists. */
+ $existing = Image::by_id($image_id);
+
+ if(is_null($existing)) {
+ throw new UploadException("Image to replace does not exist!");
+ }
+ if ($existing->hash === $event->metadata['hash']) {
+ throw new UploadException("The uploaded image is the same as the one to replace.");
+ }
+
+ // even more hax..
+ $event->metadata['tags'] = $existing->get_tag_list();
+ $image = $this->create_image_from_data(warehouse_path("images", $event->metadata['hash']), $event->metadata);
+
+ if(is_null($image)) {
+ throw new UploadException("Data handler failed to create image object from data");
+ }
+
+ $ire = new ImageReplaceEvent($image_id, $image);
+ send_event($ire);
+ $event->image_id = $image_id;
+ }
+ else
+ {
+ $image = $this->create_image_from_data(warehouse_path("images", $event->hash), $event->metadata);
+ if(is_null($image)) {
+ throw new UploadException("Data handler failed to create image object from data");
+ }
+ $iae = new ImageAdditionEvent($event->user, $image);
+ send_event($iae);
+ $event->image_id = $iae->image->id;
}
- $iae = new ImageAdditionEvent($event->user, $image);
- send_event($iae);
- $event->image_id = $iae->image->id;
}
if(($event instanceof ThumbnailGenerationEvent) && $this->supported_ext($event->type)) {
diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php
index 944d9e1c..e467e2db 100644
--- a/core/imageboard.pack.php
+++ b/core/imageboard.pack.php
@@ -457,6 +457,16 @@ class Image {
unlink($this->get_thumb_filename());
}
+ /**
+ * This function removes an image (and thumbnail) from the DISK ONLY.
+ * It DOES NOT remove anything from the database.
+ */
+ public function remove_image_only() {
+ log_info("core-image", "Removed Image File ({$this->hash})");
+ unlink($this->get_image_filename());
+ unlink($this->get_thumb_filename());
+ }
+
/**
* Someone please explain this
*
diff --git a/ext/image/main.php b/ext/image/main.php
index 86a2c71a..1908d6f5 100644
--- a/ext/image/main.php
+++ b/ext/image/main.php
@@ -46,6 +46,32 @@ class ImageDeletionEvent extends Event {
}
}
+/*
+ * ImageReplaceEvent:
+ * $id -- the ID of the image to replace
+ * $image -- the image object of the new image to use
+ *
+ * This function replaces an image. Effectively it only
+ * replaces the image file contents and leaves the tags
+ * and such the same.
+ */
+class ImageReplaceEvent extends Event {
+ var $id, $image;
+
+ public function ImageReplaceEvent($id, Image $image) {
+ $this->id = $id;
+ $this->image = $image;
+ }
+}
+
+class ImageReplaceException extends SCoreException {
+ var $error;
+
+ public function __construct($error) {
+ $this->error = $error;
+ }
+}
+
/*
* ThumbnailGenerationEvent:
@@ -129,6 +155,19 @@ class ImageIO extends SimpleExtension {
}
}
}
+ if($event->page_matches("image_admin/replace")) {
+ global $page, $user;
+ if($user->is_admin() && isset($_POST['image_id']) && $user->check_auth_token()) {
+ $image = Image::by_id($_POST['image_id']);
+ if($image) {
+ $page->set_mode("redirect");
+ $page->set_redirect(make_link('upload/replace/'.$image->id));
+ } else {
+ /* Invalid image ID */
+ throw new ImageReplaceException("Image to replace does not exist.");
+ }
+ }
+ }
}
public function onImageAdminBlockBuilding($event) {
@@ -151,6 +190,15 @@ class ImageIO extends SimpleExtension {
$event->image->delete();
}
+ public function onImageReplace($event) {
+ try {
+ $this->replace_image($event->id, $event->image);
+ }
+ catch(ImageReplaceException $e) {
+ throw new UploadException($e->error);
+ }
+ }
+
public function onUserPageBuilding($event) {
$u_id = url_escape($event->display_user->id);
$i_image_count = Image::count_images(array("user_id={$event->display_user->id}"));
@@ -266,7 +314,8 @@ class ImageIO extends SimpleExtension {
$image->tag_array = array();
send_event(new TagSetEvent($image, $tags_to_set));
}
-// }}}
+// }}} end add
+
// fetch image {{{
private function send_file($image_id, $type) {
global $config;
@@ -312,6 +361,58 @@ class ImageIO extends SimpleExtension {
"The requested image was not found in the database"));
}
}
-// }}}
-}
+// }}} end fetch
+
+// replace image {{{
+ private function replace_image($id, $image) {
+ global $page;
+ global $user;
+ global $database;
+ global $config;
+
+ /* Check to make sure the image exists. */
+ $existing = Image::by_id($id);
+
+ if(is_null($existing)) {
+ throw new ImageReplaceException("Image to replace does not exist!");
+ }
+
+ if(strlen(trim($image->source)) == 0) {
+ $image->source = $existing->get_source();
+ }
+ if(!empty($image->source)) {
+ if(!preg_match("#^(https?|ftp)://#", $image->source)) {
+ throw new ImageReplaceException("Image's source isn't a valid URL");
+ }
+ }
+
+ /*
+ This step could be optional, ie: perhaps move the image somewhere
+ and have it stored in a 'replaced images' list that could be
+ inspected later by an admin?
+ */
+ log_debug("image", "Removing image with hash ".$existing->hash);
+ $existing->remove_image_only(); // Actually delete the old image file from disk
+
+ // Update the data in the database.
+ $database->Execute(
+ "UPDATE images SET
+ filename = :filename, filesize = :filesize, hash = :hash,
+ ext = :ext, width = :width, height = :height, source = :source
+ WHERE
+ id = :id
+ ",
+ array(
+ "filename"=>$image_new->filename, "filesize"=>$image->filesize, "hash"=>$image->hash,
+ "ext"=>$image->ext, "width"=>$image->width, "height"=>$image->height, "source"=>$image->source,
+ "id"=>$id
+ )
+ );
+
+ log_info("image", "Replaced Image #{$id} with ({$image->hash})");
+ }
+// }}} end replace
+
+
+} // end of class ImageIO
?>
diff --git a/ext/image/theme.php b/ext/image/theme.php
index 10bfcfe4..516a045d 100644
--- a/ext/image/theme.php
+++ b/ext/image/theme.php
@@ -27,6 +27,16 @@ class ImageIOTheme {
";
}
+
+ if($config->get_bool("upload_replace") && $user->is_admin()) {
+ $html .= "
+ ".make_form(make_link("image_admin/replace"))."
+
+
+
+ ";
+ }
+
return $html;
}
}
diff --git a/ext/upload/main.php b/ext/upload/main.php
index ad5a8119..38ed4754 100644
--- a/ext/upload/main.php
+++ b/ext/upload/main.php
@@ -54,6 +54,7 @@ class Upload implements Extension {
$config->set_default_int('upload_count', 3);
$config->set_default_int('upload_size', '1MB');
$config->set_default_bool('upload_anon', false);
+ $config->set_default_bool('upload_replace', true);
}
if($event instanceof PostListBuildingEvent) {
@@ -67,47 +68,113 @@ class Upload implements Extension {
}
}
- if(($event instanceof PageRequestEvent) && $event->page_matches("upload")) {
- if(count($_FILES) + count($_POST) > 0) {
- $tags = Tag::explode($_POST['tags']);
- $source = isset($_POST['source']) ? $_POST['source'] : null;
- if($this->can_upload($user)) {
- $ok = true;
- foreach($_FILES as $file) {
- $ok = $ok & $this->try_upload($file, $tags, $source);
+ if($event instanceof PageRequestEvent) {
+
+ if ($event->page_matches("upload/replace"))
+ {
+ /* Upload & Replace Image Request */
+
+ if (!$config->get_bool("upload_replace")) {
+ throw new UploadException("Upload Replacing Images is not enabled.");
+ }
+
+ // check if the user is an administrator and can upload files.
+ if (!$user->is_admin() && !$this->can_upload($user)) {
+ $this->theme->display_permission_denied($page);
+ }
+ else
+ {
+ if($is_full) {
+ throw new UploadException("Can not replace Image: disk nearly full");
}
- foreach($_POST as $name => $value) {
- if(substr($name, 0, 3) == "url" && strlen($value) > 0) {
- $ok = $ok & $this->try_transload($value, $tags, $source);
+ // Try to get the image ID
+ $image_id = int_escape($event->get_arg(0));
+ if (empty($image_id)) {
+ $image_id = isset($_POST['image_id']) ? $_POST['image_id'] : null;
+ }
+ if (empty($image_id)) {
+ throw new UploadException("Can not replace Image: No valid Image ID given.");
+ }
+
+ $image_old = Image::by_id($image_id);
+ if(is_null($image_old)) {
+ $this->theme->display_error($page, "Image not found", "No image in the database has the ID #$image_id");
+ }
+
+ if(count($_FILES) + count($_POST) > 0)
+ {
+ if (count($_FILES) > 1) {
+ throw new UploadException("Can not upload more than one image for replacing.");
+ }
+
+ if (count($_FILES)) {
+ foreach($_FILES as $file) {
+ $ok = $this->try_upload($file, $tags, $source, $image_id);
+ break; // leave the foreach loop.
+ }
+ } else {
+ foreach($_POST as $name => $value) {
+ if(substr($name, 0, 3) == "url" && strlen($value) > 0) {
+ $ok = $this->try_transload($value, $tags, $source, $image_id);
+ break; // leave the foreach loop.
+ }
+ }
+ }
+ $this->theme->display_upload_status($page, $ok);
+ }
+ else if(!empty($_GET['url']))
+ {
+ $url = $_GET['url'];
+ $ok = $this->try_transload($url, $tags, $url, $image_id);
+ $this->theme->display_upload_status($page, $ok);
+ }
+ else
+ {
+ $this->theme->display_replace_page($page, $image_id);
+ }
+ } // END of if admin / can_upload
+ }
+ else if ($event->page_matches("upload"))
+ {
+ if(!$this->can_upload($user)) {
+ $this->theme->display_permission_denied($page);
+ } else {
+ /* Regular Upload Image */
+ if(count($_FILES) + count($_POST) > 0)
+ {
+ $tags = Tag::explode($_POST['tags']);
+ $source = isset($_POST['source']) ? $_POST['source'] : null;
+ $ok = true;
+ foreach($_FILES as $file) {
+ $ok = $ok & $this->try_upload($file, $tags, $source);
+ }
+ foreach($_POST as $name => $value) {
+ if(substr($name, 0, 3) == "url" && strlen($value) > 0) {
+ $ok = $ok & $this->try_transload($value, $tags, $source);
+ }
+ }
+
+ $this->theme->display_upload_status($page, $ok);
+ }
+ else if(!empty($_GET['url']))
+ {
+ $url = $_GET['url'];
+ $tags = array('tagme');
+ if(!empty($_GET['tags']) && $_GET['tags'] != "null") {
+ $tags = Tag::explode($_GET['tags']);
+ }
+ $ok = $this->try_transload($url, $tags, $url);
+ $this->theme->display_upload_status($page, $ok);
+ }
+ else
+ {
+ if(!$is_full) {
+ $this->theme->display_page($page);
}
}
-
- $this->theme->display_upload_status($page, $ok);
- }
- else {
- $this->theme->display_permission_denied($page);
- }
+ } // END of if can_upload
}
- else if(!empty($_GET['url'])) {
- if($this->can_upload($user)) {
- $url = $_GET['url'];
- $tags = array('tagme');
- if(!empty($_GET['tags']) && $_GET['tags'] != "null") {
- $tags = Tag::explode($_GET['tags']);
- }
- $ok = $this->try_transload($url, $tags, $url);
- $this->theme->display_upload_status($page, $ok);
- }
- else {
- $this->theme->display_permission_denied($page);
- }
- }
- else {
- if(!$is_full) {
- $this->theme->display_page($page);
- }
- }
- }
+ } // END of if PageRequestEvent
if($event instanceof SetupBuildingEvent) {
$tes = array();
@@ -126,6 +193,7 @@ class Upload implements Extension {
$sb->add_label("
PHP's Max Size Upload = ".ini_get('upload_max_filesize')."
");
$sb->add_shorthand_int_option("upload_size", "
Max size per file: ");
$sb->add_bool_option("upload_anon", "
Allow anonymous uploads: ");
+ $sb->add_bool_option("upload_replace", "
Allow replacing images: ");
$sb->add_choice_option("transload_engine", $tes, "
Transload: ");
$event->panel->add_block($sb);
}
@@ -172,7 +240,7 @@ class Upload implements Extension {
}
}
- private function try_upload($file, $tags, $source) {
+ private function try_upload($file, $tags, $source, $replace='') {
global $page;
global $config;
global $user;
@@ -188,15 +256,19 @@ class Upload implements Extension {
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new UploadException($this->upload_error_message($file['error']));
}
-
+
$pathinfo = pathinfo($file['name']);
$metadata['filename'] = $pathinfo['basename'];
$metadata['extension'] = $pathinfo['extension'];
$metadata['tags'] = $tags;
$metadata['source'] = $source;
+ /* check if we have been given an image ID to replace */
+ if (!empty($replace)) {
+ $metadata['replace'] = $replace;
+ }
+
$event = new DataUploadEvent($user, $file['tmp_name'], $metadata);
-
send_event($event);
if($event->image_id == -1) {
throw new UploadException("File type not recognised");
@@ -213,7 +285,7 @@ class Upload implements Extension {
return $ok;
}
- private function try_transload($url, $tags, $source) {
+ private function try_transload($url, $tags, $source, $replace='') {
global $page;
global $config;
@@ -279,6 +351,12 @@ class Upload implements Extension {
$metadata['extension'] = $pathinfo['extension'];
$metadata['tags'] = $tags;
$metadata['source'] = $source;
+
+ /* check if we have been given an image ID to replace */
+ if (!empty($replace)) {
+ $metadata['replace'] = $replace;
+ }
+
$event = new DataUploadEvent($user, $tmp_filename, $metadata);
try {
send_event($event);
diff --git a/ext/upload/theme.php b/ext/upload/theme.php
index aaf88dfe..df0e5868 100644
--- a/ext/upload/theme.php
+++ b/ext/upload/theme.php
@@ -75,6 +75,53 @@ class UploadTheme extends Themelet {
$page->add_block(new Block("Upload", $html, "main", 20));
}
+ /* only allows 1 file to be uploaded - for replacing another image file */
+ public function display_replace_page(Page $page, $image_id) {
+ global $config;
+ $tl_enabled = ($config->get_string("transload_engine", "none") != "none");
+
+ $upload_list = '';
+ $width = $tl_enabled ? "35%" : "80%";
+ $upload_list .= "
+
Replacing Image ID ".$image_id."
Please note: You will have to refresh the image page, or empty your browser cache.
Source | |||