diff --git a/core/events/dataupload.event.php b/core/events/dataupload.event.php new file mode 100644 index 00000000..3fb78cfa --- /dev/null +++ b/core/events/dataupload.event.php @@ -0,0 +1,23 @@ +user = $user; + $this->tmpname = $tmpname; + + $this->metadata = $metadata; + $this->metadata['hash'] = md5_file($tmpname); + $this->metadata['size'] = filesize($tmpname); + + // useful for most file handlers, so pull directly into fields + $this->hash = $this->metadata['hash']; + $this->type = strtolower($metadata['extension']); + } +} +?> diff --git a/core/events/imageaddition.event.php b/core/events/imageaddition.event.php new file mode 100644 index 00000000..45765a4d --- /dev/null +++ b/core/events/imageaddition.event.php @@ -0,0 +1,16 @@ +image = $image; + $this->user = $user; + } +} +?> diff --git a/core/events/thumbnailgeneration.event.php b/core/events/thumbnailgeneration.event.php new file mode 100644 index 00000000..bfa03794 --- /dev/null +++ b/core/events/thumbnailgeneration.event.php @@ -0,0 +1,15 @@ +hash = $hash; + $this->type = $type; + } +} +?> diff --git a/core/events/uploadingimage.event.php b/core/events/uploadingimage.event.php deleted file mode 100644 index 5bef2b83..00000000 --- a/core/events/uploadingimage.event.php +++ /dev/null @@ -1,17 +0,0 @@ -image = $image; - $this->user = $user; - } -} -?> diff --git a/core/image.class.php b/core/image.class.php index f1dc9f28..288fc40d 100644 --- a/core/image.class.php +++ b/core/image.class.php @@ -9,13 +9,10 @@ class Image { var $posted; var $source; - public function Image($a=false, $b=false, $c=array(), $d="") { - if($b == false) { + public function Image($a=null) { + if(!is_null($a)) { $this->create_from_row($a); } - else { - $this->create_from_data($a, $b, $c, $d); - } } private function create_from_row($row) { @@ -24,43 +21,6 @@ class Image { } } - private function mime_to_ext($mime) { - switch($mime) { - default: - case 'image/jpeg': return "jpg"; break; - case 'image/png': return "png"; break; - case 'image/gif': return "gif"; break; - } - } - - private function create_from_data($tmp, $filename, $tags, $source) { - global $config; - - $this->ok = false; - $info = ""; - - if(!file_exists($tmp)) return; - if(filesize($tmp) > $config->get_int('upload_size')) return; - if(!($info = getimagesize($tmp))) return; - - $this->width = $info[0]; - $this->height = $info[1]; - $this->mime_type = $info['mime']; - $this->filename = str_replace("/", "_", $filename); // is this even possible? - $this->filesize = filesize($tmp); - $this->ext = $this->mime_to_ext($info['mime']); - $this->hash = md5_file($tmp); - $this->temp_filename = $tmp; - $this->tag_array = tag_explode($tags); - $this->source = $source; - - $this->ok = true; - } - - public function is_ok() { - return $this->ok; - } - public function get_owner() { global $database; return $database->get_user_by_id($this->owner_id); diff --git a/ext/handle_pixel/main.php b/ext/handle_pixel/main.php new file mode 100644 index 00000000..591946c7 --- /dev/null +++ b/ext/handle_pixel/main.php @@ -0,0 +1,150 @@ + + * Description: Handle JPG, PNG, GIF, etc files + */ + +class PixelFileHandler extends Extension { + var $theme; + + public function receive_event($event) { + if(is_null($this->theme)) $this->theme = get_theme_object("handle_pixel", "PixelFileHandlerTheme"); + + if(is_a($event, 'DataUploadEvent') && $this->supported_ext($event->type) && $this->check_contents($event->tmpname)) { + $hash = $event->hash; + $ha = substr($hash, 0, 2); + if(!copy($event->tmpname, "images/$ha/$hash")) { + $event->veto("Pixel Handler failed to move file from uploads to archive"); + return; + } + send_event(new ThumbnailGenerationEvent($event->hash, $event->type)); + $image = $this->create_image_from_data("images/$ha/$hash", $event->metadata); + if(is_null($image)) { + $event->veto("Pixel Handler failed to create image object from data"); + return; + } + send_event(new ImageAdditionEvent($event->user, $image)); + } + + if(is_a($event, 'ThumbnailGenerationEvent') && $this->supported_ext($event->type)) { + $this->create_thumb($event->hash); + } + + if(is_a($event, 'DisplayingImageEvent') && $this->supported_ext($event->image->ext)) { + $this->theme->display_image($event->page, $event->image); + } + } + + private function supported_ext($ext) { + $exts = array("jpg", "jpeg", "gif", "png"); + foreach($exts as $supported) { + if($ext == $supported) return true; + } + return false; + } + + private function create_image_from_data($filename, $metadata) { + global $config; + + $image = new Image(); + + $info = ""; + if(!($info = getimagesize($filename))) return null; + + $image->width = $info[0]; + $image->height = $info[1]; + + $image->filesize = $metadata['size']; + $image->hash = $metadata['hash']; + $image->filename = $metadata['filename']; + $image->ext = $metadata['extension']; + $image->tag_array = tag_explode($metadata['tags']); + $image->source = $metadata['source']; + + return $image; + } + + private function check_contents($file) { + return (file_exists($file) && !is_null(getimagesize($file))); + } + + private function create_thumb($hash) { + $ha = substr($hash, 0, 2); + $inname = "images/$ha/$hash"; + $outname = "thumbs/$ha/$hash"; + global $config; + + $ok = false; + + switch($config->get_string("thumb_engine")) { + default: + case 'gd': + $ok = $this->make_thumb_gd($inname, $outname); + break; + case 'convert': + $ok = $this->make_thumb_convert($inname, $outname); + break; + } + + return $ok; + } + +// IM thumber {{{ + private function make_thumb_convert($inname, $outname) { + global $config; + + $w = $config->get_int("thumb_width"); + $h = $config->get_int("thumb_height"); + $q = $config->get_int("thumb_quality"); + $mem = $config->get_int("thumb_max_memory") / 1024 / 1024; // IM takes memory in MB + + // "-limit memory $mem" broken? + exec("convert {$inname}[0] -geometry {$w}x{$h} -quality {$q} jpg:$outname"); + + return true; + } +// }}} +// GD thumber {{{ + private function make_thumb_gd($inname, $outname) { + global $config; + $thumb = $this->get_thumb($inname); + return imagejpeg($thumb, $outname, $config->get_int('thumb_quality')); + } + + private function get_thumb($tmpname) { + global $config; + + $info = getimagesize($tmpname); + $width = $info[0]; + $height = $info[1]; + + $memory_use = (filesize($tmpname)*2) + ($width*$height*4) + (4*1024*1024); + $memory_limit = get_memory_limit(); + + if($memory_use > $memory_limit) { + $w = $config->get_int('thumb_width'); + $h = $config->get_int('thumb_height'); + $thumb = imagecreatetruecolor($w, min($h, 64)); + $white = imagecolorallocate($thumb, 255, 255, 255); + $black = imagecolorallocate($thumb, 0, 0, 0); + imagefill($thumb, 0, 0, $white); + imagestring($thumb, 5, 10, 24, "Image Too Large :(", $black); + return $thumb; + } + else { + $image = imagecreatefromstring($this->read_file($tmpname)); + $tsize = get_thumbnail_size($width, $height); + + $thumb = imagecreatetruecolor($tsize[0], $tsize[1]); + imagecopyresampled( + $thumb, $image, 0, 0, 0, 0, + $tsize[0], $tsize[1], $width, $height + ); + return $thumb; + } + } +// }}} +} +add_event_listener(new PixelFileHandler()); +?> diff --git a/ext/handle_pixel/theme.php b/ext/handle_pixel/theme.php new file mode 100644 index 00000000..def60f0e --- /dev/null +++ b/ext/handle_pixel/theme.php @@ -0,0 +1,10 @@ +get_image_link(); + $html = ""; + $page->add_block(new Block("Image", $html, "main", 0)); + } +} +?> diff --git a/ext/image/main.php b/ext/image/main.php index 70f7a5c2..304e19e4 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -33,7 +33,7 @@ class ImageIO extends Extension { } } - if(is_a($event, 'UploadingImageEvent')) { + if(is_a($event, 'ImageAdditionEvent')) { $error = $this->add_image($event->image); if(!empty($error)) $event->veto($error); } @@ -87,80 +87,6 @@ class ImageIO extends Extension { return $data; } - private function make_thumb($inname, $outname) { - global $config; - - $ok = false; - - switch($config->get_string("thumb_engine")) { - default: - case 'gd': - $ok = $this->make_thumb_gd($inname, $outname); - break; - case 'convert': - $ok = $this->make_thumb_convert($inname, $outname); - break; - } - - return $ok; - } - -// IM thumber {{{ - private function make_thumb_convert($inname, $outname) { - global $config; - - $w = $config->get_int("thumb_width"); - $h = $config->get_int("thumb_height"); - $q = $config->get_int("thumb_quality"); - $mem = $config->get_int("thumb_max_memory") / 1024 / 1024; // IM takes memory in MB - - // "-limit memory $mem" broken? - exec("convert {$inname}[0] -geometry {$w}x{$h} -quality {$q} jpg:$outname"); - - return true; - } -// }}} -// GD thumber {{{ - private function make_thumb_gd($inname, $outname) { - global $config; - $thumb = $this->get_thumb($inname); - return imagejpeg($thumb, $outname, $config->get_int('thumb_quality')); - } - - private function get_thumb($tmpname) { - global $config; - - $info = getimagesize($tmpname); - $width = $info[0]; - $height = $info[1]; - - $memory_use = (filesize($tmpname)*2) + ($width*$height*4) + (4*1024*1024); - $memory_limit = get_memory_limit(); - - if($memory_use > $memory_limit) { - $w = $config->get_int('thumb_width'); - $h = $config->get_int('thumb_height'); - $thumb = imagecreatetruecolor($w, min($h, 64)); - $white = imagecolorallocate($thumb, 255, 255, 255); - $black = imagecolorallocate($thumb, 0, 0, 0); - imagefill($thumb, 0, 0, $white); - imagestring($thumb, 5, 10, 24, "Image Too Large :(", $black); - return $thumb; - } - else { - $image = imagecreatefromstring($this->read_file($tmpname)); - $tsize = get_thumbnail_size($width, $height); - - $thumb = imagecreatetruecolor($tsize[0], $tsize[1]); - imagecopyresampled( - $thumb, $image, 0, 0, 0, 0, - $tsize[0], $tsize[1], $width, $height - ); - return $thumb; - } - } -// }}} - private function add_image($image) { global $page; global $user; @@ -200,28 +126,6 @@ class ImageIO extends Extension { $image->hash, $image->ext, $image->width, $image->height, $image->source)); $image->id = $database->db->Insert_ID(); - /* - * If no errors: move the file from the temporary upload - * area to the main file store, create a thumbnail, and - * insert the image info into the database - */ - if(!copy($image->temp_filename, $image->get_image_filename())) { - send_event(new ImageDeletionEvent($image->id)); - $error = "The image couldn't be moved from the temporary area to the - main data store -- is the web server allowed to write to '". - ($image->get_image_filename())."'?"; - return $error; - } - chmod($image->get_image_filename(), 0644); - - if(!$this->make_thumb($image->get_image_filename(), $image->get_thumb_filename())) { - send_event(new ImageDeletionEvent($image->id)); - $error="The image thumbnail couldn't be generated -- is the web - server allowed to write to '".($image->get_thumb_filename())."'?"; - return $error; - } - chmod($image->get_thumb_filename(), 0644); - send_event(new TagSetEvent($image->id, $image->get_tag_array())); return null; diff --git a/ext/regen_thumb/main.php b/ext/regen_thumb/main.php index 0379ca96..b847880a 100644 --- a/ext/regen_thumb/main.php +++ b/ext/regen_thumb/main.php @@ -2,14 +2,17 @@ class RegenThumb extends Extension { var $theme; -// event handler {{{ + public function receive_event($event) { if(is_null($this->theme)) $this->theme = get_theme_object("regen_thumb", "RegenThumbTheme"); if(is_a($event, 'PageRequestEvent') && ($event->page_name == "regen_thumb")) { global $user; - if($user->is_admin() && isset($_POST['program']) && isset($_POST['image_id'])) { - $this->make_thumb($_POST['program'], $_POST['image_id']); + if($user->is_admin() && isset($_POST['image_id'])) { + global $database; + $image = $database->get_image(int_escape($_POST['image_id'])); + send_event(new ThumbnailGenerationEvent($image->hash, $image->ext)); + $this->theme->display_results($event->page, $image); } } @@ -20,96 +23,6 @@ class RegenThumb extends Extension { } } } -// }}} -// do things {{{ - // FIXME: make locations of convert / epeg config variables - private function make_thumb($program, $image_id) { - global $database; - global $config; - - $i_image_id = int_escape($image_id); - $image = $database->get_image($i_image_id); - - $f_image = $this->check_filename($image->get_image_filename()); - $f_thumb = $this->check_filename($image->get_thumb_filename()); - - $w = $config->get_int('thumb_width'); - $h = $config->get_int('thumb_height'); - $q = $config->get_int('thumb_quality'); - - switch($program) { - case 'convert': - if(file_exists($f_thumb)) unlink($f_thumb); - $mem = $config->get_int("thumb_max_memory") / 1024 / 1024; // IM takes memory in MB - // "-limit memory $mem" broken? - exec("convert {$f_image}[0] -geometry {$w}x{$h} -quality {$q} jpg:$f_thumb"); - break; - case 'gd': - $this->make_thumb_gd($f_image, $f_thumb); - break; - default: - break; - } - - global $page; - $this->theme->display_results($page, $image); - } - - private function check_filename($filename) { - $filename = preg_replace("#[^a-zA-Z0-9/\._]#", "", $filename); - return $filename; - } - -// }}} -// GD thumber {{{ - private function read_file($fname) { - $fp = fopen($fname, "r"); - if(!$fp) return false; - - $data = fread($fp, filesize($fname)); - fclose($fp); - - return $data; - } - private function make_thumb_gd($inname, $outname) { - global $config; - $thumb = $this->get_thumb($inname); - return imagejpeg($thumb, $outname, $config->get_int('thumb_quality')); - } - - private function get_thumb($tmpname) { - global $config; - - $info = getimagesize($tmpname); - $width = $info[0]; - $height = $info[1]; - - $memory_use = (filesize($tmpname)*2) + ($width*$height*4) + (4*1024*1024); - $memory_limit = get_memory_limit(); - - if($memory_use > $memory_limit) { - $w = $config->get_int('thumb_width'); - $h = $config->get_int('thumb_height'); - $thumb = imagecreatetruecolor($w, min($h, 64)); - $white = imagecolorallocate($thumb, 255, 255, 255); - $black = imagecolorallocate($thumb, 0, 0, 0); - imagefill($thumb, 0, 0, $white); - imagestring($thumb, 5, 10, 24, "Image Too Large :(", $black); - return $thumb; - } - else { - $image = imagecreatefromstring($this->read_file($tmpname)); - $tsize = get_thumbnail_size($width, $height); - - $thumb = imagecreatetruecolor($tsize[0], $tsize[1]); - imagecopyresampled( - $thumb, $image, 0, 0, 0, 0, - $tsize[0], $tsize[1], $width, $height - ); - return $thumb; - } - } -// }}} } add_event_listener(new RegenThumb()); ?> diff --git a/ext/regen_thumb/theme.php b/ext/regen_thumb/theme.php index a479cfd8..d5af9a72 100644 --- a/ext/regen_thumb/theme.php +++ b/ext/regen_thumb/theme.php @@ -8,11 +8,6 @@ class RegenThumbTheme extends Themelet { $html = "
-
"; diff --git a/ext/upload/main.php b/ext/upload/main.php index f5839939..6435ddef 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -60,6 +60,13 @@ class Upload extends Extension { ), "
Transload: "); $event->panel->add_block($sb); } + + if(is_a($event, "DataUploadEvent")) { + global $config; + if(filesize($tmp_filename) > $config->get_int('upload_size')) { + $event->veto("File too large (".filesize($tmp_filename)." > ".($config->get_int('upload_size')).")"); + } + } } // }}} // do things {{{ @@ -74,37 +81,22 @@ class Upload extends Extension { if(empty($source)) $source = null; - $ok = false; + $ok = true; - if(!file_exists($file['tmp_name'])) { - // this happens normally with blank file boxes - $ok = true; - } - else if(filesize($file['tmp_name']) > $config->get_int('upload_size')) { - $this->theme->display_upload_error($page, "Error with ".html_escape($file['name']), - "File too large (".to_shorthand_int(filesize($file['tmp_name']))." > ". - (to_shorthand_int($config->get_int('upload_size'))).")"); - } - else if(!($info = getimagesize($file['tmp_name']))) { - $this->theme->display_upload_error($page, "Error with ".html_escape($file['name']), - "PHP doesn't recognise this as an image file"); - } - else { - $image = new Image($file['tmp_name'], $file['name'], $tags, $source); - - if($image->is_ok()) { - global $user; - $event = new UploadingImageEvent($user, $image); - send_event($event); - $ok = !$event->vetoed; - if(!$ok) { - $this->theme->display_upload_error($page, "Error with ".html_escape($file['name']), - $event->veto_reason); - } - } - else { + // blank file boxes cause empty uploads, no need for error message + if(file_exists($file['tmp_name'])) { + global $user; + $pathinfo = pathinfo($file['name']); + $metadata['filename'] = $pathinfo['basename']; + $metadata['extension'] = $pathinfo['extension']; + $metadata['tags'] = $tags; + $metadata['source'] = $source; + $event = new DataUploadEvent($user, $file['tmp_name'], $metadata); + send_event($event); + if($event->vetoed) { $this->theme->display_upload_error($page, "Error with ".html_escape($file['name']), - "Something is not right!"); + $event->veto_reason); + $ok = false; } } @@ -115,7 +107,7 @@ class Upload extends Extension { global $page; global $config; - $ok = false; + $ok = true; if(empty($source)) $source = $url; @@ -161,32 +153,21 @@ class Upload extends Extension { if(filesize($tmp_filename) == 0) { $this->theme->display_upload_error($page, "Error with ".html_escape($filename), "No data found -- perhaps the site has hotlink protection?"); - } - else if(filesize($tmp_filename) > $config->get_int('upload_size')) { - $this->theme->display_upload_error($page, "Error with ".html_escape($filename), - "File too large (".filesize($tmp_filename)." > ". - ($config->get_int('upload_size')).")"); - } - else if(!($info = @getimagesize($tmp_filename))) { - $this->theme->display_upload_error($page, "Error with ".html_escape($filename), - "PHP doesn't recognise this as an image file -- perhaps the site has hotlink protection?"); + $ok = false; } else { - $image = new Image($tmp_filename, basename($url), $tags, $source); - - if($image->is_ok()) { - global $user; - $event = new UploadingImageEvent($user, $image); - send_event($event); - $ok = !$event->vetoed; - if(!$ok) { - $this->theme->display_upload_error($page, "Error with ".html_escape($filename), - $event->veto_reason); - } - } - else { - $this->theme->display_upload_error($page, "Error with ".html_escape($filename), - "Something is not right!"); + global $user; + $pathinfo = pathinfo($file); + $metadata['filename'] = $pathinfo['basename']; + $metadata['extension'] = $pathinfo['extension']; + $metadata['tags'] = $tags; + $metadata['source'] = $source; + $event = new DataUploadEvent($user, $tmp_filename, $metadata); + send_event($event); + if($event->vetoed) { + $this->theme->display_upload_error($page, "Error with ".html_escape($file['name']), + $event->veto_reason); + $ok = false; } } @@ -196,5 +177,5 @@ class Upload extends Extension { } // }}} } -add_event_listener(new Upload()); +add_event_listener(new Upload(), 40); // early, so it can veto the DataUploadEvent before any data handlers see it ?> diff --git a/ext/view/theme.php b/ext/view/theme.php index 9e79d398..efffb47a 100644 --- a/ext/view/theme.php +++ b/ext/view/theme.php @@ -8,7 +8,6 @@ class ViewTheme extends Themelet { $page->set_title("Image {$image->id}: ".html_escape($image->get_tag_list())); $page->set_heading(html_escape($image->get_tag_list())); $page->add_block(new Block("Navigation", $this->build_navigation($image->id), "left", 0)); - $page->add_block(new Block("Image", $this->build_image_view($image), "main", 0)); $page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 10)); $page->add_block(new Block(null, $this->build_pin($image->id), "main", 11)); } @@ -56,11 +55,6 @@ class ViewTheme extends Themelet { return "$h_pin
$h_search"; } - protected function build_image_view($image) { - $ilink = $image->get_image_link(); - return ""; - } - protected function build_info($image, $editor_parts) { global $user; $owner = $image->get_owner();