Merge branch 'master' of github.com:shish/shimmie2

This commit is contained in:
Shish 2011-09-25 12:45:59 +01:00
commit a1da59804e
32 changed files with 647 additions and 150 deletions

View File

@ -28,7 +28,7 @@ class BrowserSearch implements Extension {
global $config;
$search_title = $config->get_string('title');
$search_file_url = make_link('browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml');
$page->add_header("<link rel='search' type='application/opensearchdescription+xml' title='$search_title' href='$search_file_url'>");
$page->add_html_header("<link rel='search' type='application/opensearchdescription+xml' title='$search_title' href='$search_file_url'>");
}
// The search.xml file that is generated on the fly

View File

@ -159,8 +159,8 @@ class DanbooruApi implements Extension
{
$fp = fopen($url, "r");
if(!$fp) {
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: fopen read error");
$page->add_http_header("HTTP/1.0 409 Conflict");
$page->add_http_header("X-Danbooru-Errors: fopen read error");
}
$data = "";
@ -193,8 +193,8 @@ class DanbooruApi implements Extension
$filename = basename($url);
} else
{ // Nothing was specified at all
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: no input files");
$page->add_http_header("HTTP/1.0 409 Conflict");
$page->add_http_header("X-Danbooru-Errors: no input files");
return;
}
@ -206,8 +206,8 @@ class DanbooruApi implements Extension
{
if(strtolower($_REQUEST['md5']) != $hash)
{
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: md5 mismatch");
$page->add_http_header("HTTP/1.0 409 Conflict");
$page->add_http_header("X-Danbooru-Errors: md5 mismatch");
return;
}
}
@ -217,11 +217,11 @@ class DanbooruApi implements Extension
// Does it exist already?
$existing = Image::by_hash($hash);
if(!is_null($existing)) {
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: duplicate");
$page->add_http_header("HTTP/1.0 409 Conflict");
$page->add_http_header("X-Danbooru-Errors: duplicate");
$existinglink = make_link("post/view/" . $existing->id);
if($danboorup_kludge) $existinglink=make_http($existinglink);
header("X-Danbooru-Location: $existinglink");
$page->add_http_header("X-Danbooru-Location: $existinglink");
return; // wut!
}
@ -246,21 +246,21 @@ class DanbooruApi implements Extension
// Did we POST or GET this call?
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
header("X-Danbooru-Location: $newid");
$page->add_http_header("X-Danbooru-Location: $newid");
}
else
header("Location: $newid");
$page->add_http_header("Location: $newid");
}
catch(UploadException $ex) {
// Did something screw up?
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: exception - " . $ex->getMessage());
$page->add_http_header("HTTP/1.0 409 Conflict");
$page->add_http_header("X-Danbooru-Errors: exception - " . $ex->getMessage());
return;
}
} else
{
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: authentication error");
$page->add_http_header("HTTP/1.0 409 Conflict");
$page->add_http_header("X-Danbooru-Errors: authentication error");
return;
}
}
@ -387,7 +387,7 @@ class DanbooruApi implements Extension
if(($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'show'))
{
$fixedlocation = make_link("post/view/" . $event->get_arg(3));
header("Location: $fixedlocation");
$page->add_http_header("Location: $fixedlocation");
}
}

View File

@ -19,7 +19,7 @@ class RegenThumbTheme extends Themelet {
public function display_results(Page $page, Image $image) {
$page->set_title("Thumbnail Regenerated");
$page->set_heading("Thumbnail Regenerated");
$page->add_header("<meta http-equiv=\"cache-control\" content=\"no-cache\">");
$page->add_html_header("<meta http-equiv=\"cache-control\" content=\"no-cache\">");
$page->add_block(new NavBlock());
$page->add_block(new Block("Thumbnail", $this->build_thumb_html($image)));
}

247
contrib/resize/main.php Normal file
View File

@ -0,0 +1,247 @@
<?php
/*
* Name: Resize Image
* Author: jgen <jgen.tech@gmail.com>
* Description: Allows admins to resize images.
* License: GPLv2
* Version: 0.1
* Notice:
* The image resize and resample code is based off of the "smart_resize_image"
* function copyright 2008 Maxim Chernyak, released under a MIT-style license.
* Documentation:
* This extension allows admins to resize images.
*/
/**
* This class is just a wrapper around SCoreException.
*/
class ImageResizeException extends SCoreException {
var $error;
public function __construct($error) {
$this->error = $error;
}
}
/**
* This class handles image resize requests.
*/
class ResizeImage extends SimpleExtension {
public function onInitExt($event) {
global $config;
$config->set_default_bool('resize_enabled', true);
$config->set_default_int('resize_default_width', 0);
$config->set_default_int('resize_default_height', 0);
}
public function onImageAdminBlockBuilding($event) {
global $user, $config;
if($user->is_admin() && $config->get_bool("resize_enabled")) {
/* Add a link to resize the image */
$event->add_part($this->theme->get_resize_html($event->image->id));
}
}
public function onSetupBuilding($event) {
$sb = new SetupBlock("Image Resize");
$sb->add_bool_option("resize_enabled", "Allow resizing images: ");
$sb->add_label("<br>Preset/Default Width: ");
$sb->add_int_option("resize_default_width");
$sb->add_label(" px");
$sb->add_label("<br>Preset/Default Height: ");
$sb->add_int_option("resize_default_height");
$sb->add_label(" px");
$sb->add_label("<br>(enter 0 for no default)");
$event->panel->add_block($sb);
}
public function onPageRequest($event) {
global $page, $user;
if ( $event->page_matches("resize") && $user->is_admin() ) {
// 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 ImageResizeException("Can not resize Image: No valid Image ID given.");
}
$image = Image::by_id($image_id);
if(is_null($image)) {
$this->theme->display_error($page, "Image not found", "No image in the database has the ID #$image_id");
} else {
/* Check if options were given to resize an image. */
if (isset($_POST['resize_width']) || isset($_POST['resize_height'])) {
/* get options */
$width = $height = 0;
if (isset($_POST['resize_width'])) {
$width = int_escape($_POST['resize_width']);
}
if (isset($_POST['resize_height'])) {
$height = int_escape($_POST['resize_height']);
}
/* Attempt to resize the image */
try {
$this->resize_image($image_id, $width, $height);
//$this->theme->display_resize_page($page, $image_id);
$page->set_mode("redirect");
$page->set_redirect(make_link("post/view/".$image_id));
} catch (ImageResizeException $e) {
$this->theme->display_resize_error($page, "Error Resizing", $e->error);
}
} else {
/* Display options for resizing */
$this->theme->display_resize_page($page, $image_id);
}
}
}
}
// Private functions
/*
This function could be made much smaller by using the ImageReplaceEvent
ie: Pretend that we are replacing the image with a resized copy.
*/
private function resize_image($image_id, $width, $height) {
global $config;
global $user;
global $page;
global $database;
if ( ($height <= 0) && ($width <= 0) ) {
throw new ImageResizeException("Invalid options for height and width. ($width x $height)");
}
$image_obj = Image::by_id($image_id);
$hash = $image_obj->hash;
if (is_null($hash)) {
throw new ImageResizeException("Image does not have a hash associated with it.");
}
$image_filename = warehouse_path("images", $hash);
$info = getimagesize($image_filename);
/* Get the image file type */
$pathinfo = pathinfo($image_obj->filename);
$filetype = strtolower($pathinfo['extension']);
if (($image_obj->width != $info[0] ) || ($image_obj->height != $info[1])) {
throw new ImageResizeException("The image size does not match what is in the database! - Aborting Resize.");
}
/* Check memory usage limits */
$memory_use = (filesize($image_filename)*2) + ($width*$height*4) + (4*1024*1024);
$memory_limit = get_memory_limit();
if ($memory_use > $memory_limit) {
throw new ImageResizeException("The image is too large to resize given the memory limits. ($memory_use > $memory_limit)");
}
/* Calculate the new size of the image */
if ( $height > 0 && $width > 0 ) {
$new_height = $height;
$new_width = $width;
} else {
// Scale the new image
if ($width == 0) $factor = $height/$image_obj->height;
elseif ($height == 0) $factor = $width/$image_obj->width;
else $factor = min( $width / $image_obj->width, $height / $image_obj->height );
$new_width = round( $image_obj->width * $factor );
$new_height = round( $image_obj->height * $factor );
}
/* Attempt to load the image */
switch ( $info[2] ) {
case IMAGETYPE_GIF: $image = imagecreatefromgif($image_filename); break;
case IMAGETYPE_JPEG: $image = imagecreatefromjpeg($image_filename); break;
case IMAGETYPE_PNG: $image = imagecreatefrompng($image_filename); break;
default:
throw new ImageResizeException("Unsupported image type.");
}
/* Resize and resample the image */
$image_resized = imagecreatetruecolor( $new_width, $new_height );
if ( ($info[2] == IMAGETYPE_GIF) || ($info[2] == IMAGETYPE_PNG) ) {
$transparency = imagecolortransparent($image);
if ($transparency >= 0) {
$transparent_color = imagecolorsforindex($image, $trnprt_indx);
$transparency = imagecolorallocate($image_resized, $trnprt_color['red'], $trnprt_color['green'], $trnprt_color['blue']);
imagefill($image_resized, 0, 0, $transparency);
imagecolortransparent($image_resized, $transparency);
}
elseif ($info[2] == IMAGETYPE_PNG) {
imagealphablending($image_resized, false);
$color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127);
imagefill($image_resized, 0, 0, $color);
imagesavealpha($image_resized, true);
}
}
imagecopyresampled($image_resized, $image, 0, 0, 0, 0, $new_width, $new_height, $image_obj->width, $image_obj->height);
/* Temp storage while we resize */
$tmp_filename = tempnam("/tmp", 'shimmie_resize');
if (empty($tmp_filename)) {
throw new ImageResizeException("Unable to save temporary image file.");
}
/* Output to the same format as the original image */
switch ( $info[2] ) {
case IMAGETYPE_GIF: imagegif($image_resized, $tmp_filename); break;
case IMAGETYPE_JPEG: imagejpeg($image_resized, $tmp_filename); break;
case IMAGETYPE_PNG: imagepng($image_resized, $tmp_filename); break;
default:
throw new ImageResizeException("Unsupported image type.");
}
/* Move the new image into the main storage location */
$new_hash = md5_file($tmp_filename);
$new_size = filesize($tmp_filename);
$target = warehouse_path("images", $new_hash);
if(!file_exists(dirname($target))) mkdir(dirname($target), 0755, true);
if(!@copy($tmp_filename, $target)) {
throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)");
}
$new_filename = 'resized-'.$image_obj->filename;
/* Remove temporary file */
@unlink($tmp_filename);
/* Delete original image and thumbnail */
log_debug("image", "Removing image with hash ".$hash);
$image_obj->remove_image_only();
/* Generate new thumbnail */
send_event(new ThumbnailGenerationEvent($new_hash, $filetype));
/* Update the database */
$database->Execute(
"UPDATE images SET
filename = :filename, filesize = :filesize, hash = :hash, width = :width, height = :height
WHERE
id = :id
",
array(
"filename"=>$new_filename, "filesize"=>$new_size, "hash"=>$new_hash,
"width"=>$new_width, "height"=>$new_height, "id"=>$image_id
)
);
log_info("resize", "Resized Image #{$image_id} - New hash: {$new_hash}");
}
}
?>

5
contrib/resize/style.css Normal file
View File

@ -0,0 +1,5 @@
form#form_resize {
float: left;
margin: 0;
width: 60%;
}

60
contrib/resize/theme.php Normal file
View File

@ -0,0 +1,60 @@
<?php
class ResizeImageTheme extends Themelet {
/*
* Display a link to resize an image
*/
public function get_resize_html($image_id) {
global $user;
global $config;
$i_image_id = int_escape($image_id);
$html = "
".make_form(make_link("resize"),'POST',false,'resize_image')."
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='submit' value='Resize' id='resize_image_submit' />
</form>
";
return $html;
}
public function display_resize_error(Page $page, $title, $message) {
$page->set_title("Resize Image");
$page->set_heading("Resize Image");
$page->add_block(new NavBlock());
$page->add_block(new Block($title, $message));
}
public function display_resize_page(Page $page, $image_id) {
global $config;
$default_width = $config->get_int('resize_default_width');
$default_height = $config->get_int('resize_default_height');
$image = Image::by_id($image_id);
$thumbnail = $this->build_thumb_html($image, null);
$html = "<div style='clear:both;'></div>
<p>Resize Image ID ".$image_id."<br>".$thumbnail."</p>
<p>Please note: You will have to refresh the image page, or empty your browser cache.</p>
<p>Enter the new size for the image, or leave blank to scale the image automatically.</p><br>"
.make_form(make_link('resize/'.$image_id), 'POST', $multipart=True,'form_resize')."
<input type='hidden' name='image_id' value='$image_id'>
<table id='large_upload_form'>
<tr><td>New Width</td><td colspan='3'><input id='resize_width' name='resize_width' type='text' value='".$default_width."'></td></tr>
<tr><td>New Height</td><td colspan='3'><input id='resize_height' name='resize_height' type='text' value='".$default_height."'></td></tr>
<tr><td colspan='4'><input id='resizebutton' type='submit' value='Resize'></td></tr>
</table>
</form>
";
$page->set_title("Resize Image");
$page->set_heading("Resize Image");
$page->add_block(new NavBlock());
$page->add_block(new Block("Resize Image", $html, "main", 20));
}
}
?>

View File

@ -11,7 +11,7 @@ class RSS_Comments extends SimpleExtension {
global $config, $page;
$title = $config->get_string('title');
$page->add_header("<link rel=\"alternate\" type=\"application/rss+xml\" ".
$page->add_html_header("<link rel=\"alternate\" type=\"application/rss+xml\" ".
"title=\"$title - Comments\" href=\"".make_link("rss/comments")."\" />");
}

View File

@ -13,11 +13,11 @@ class RSS_Images extends SimpleExtension {
if(count($event->search_terms) > 0) {
$search = html_escape(implode(' ', $event->search_terms));
$page->add_header("<link id=\"images\" rel=\"alternate\" type=\"application/rss+xml\" ".
$page->add_html_header("<link id=\"images\" rel=\"alternate\" type=\"application/rss+xml\" ".
"title=\"$title - Images with tags: $search\" href=\"".make_link("rss/images/$search/1")."\" />");
}
else {
$page->add_header("<link id=\"images\" rel=\"alternate\" type=\"application/rss+xml\" ".
$page->add_html_header("<link id=\"images\" rel=\"alternate\" type=\"application/rss+xml\" ".
"title=\"$title - Images\" href=\"".make_link("rss/images/1")."\" />");
}
}

View File

@ -14,11 +14,11 @@ class SiteDescription extends SimpleExtension {
global $config, $page;
if(strlen($config->get_string("site_description")) > 0) {
$description = $config->get_string("site_description");
$page->add_header("<meta name=\"description\" content=\"$description\">");
$page->add_html_header("<meta name=\"description\" content=\"$description\">");
}
if(strlen($config->get_string("site_keywords")) > 0) {
$keywords = $config->get_string("site_keywords");
$page->add_header("<meta name=\"keywords\" content=\"$keywords\">");
$page->add_html_header("<meta name=\"keywords\" content=\"$keywords\">");
}
}

View File

@ -130,9 +130,9 @@ class Tag_History implements Extension {
}
// lets get the values out of the result
$stored_result_id = $result->fields['id'];
$stored_image_id = $result->fields['image_id'];
$stored_tags = $result->fields['tags'];
$stored_result_id = $result['id'];
$stored_image_id = $result['image_id'];
$stored_tags = $result['tags'];
log_debug("tag_history", "Reverting tags of $stored_image_id to [$stored_tags]");
// all should be ok so we can revert by firing the SetUserTags event.
@ -146,7 +146,7 @@ class Tag_History implements Extension {
public function get_tag_history_from_revert($revert_id)
{
global $database;
$row = $database->execute("
$row = $database->get_row("
SELECT tag_histories.*, users.name
FROM tag_histories
JOIN users ON tag_histories.user_id = users.id
@ -201,19 +201,28 @@ class Tag_History implements Extension {
$old_tags = Tag::implode($image->get_tag_array());
log_debug("tag_history", "adding tag history: [$old_tags] -> [$new_tags]");
if($new_tags == $old_tags) return;
// add a history entry
$allowed = $config->get_int("history_limit");
if($allowed == 0) return;
// if the image has no history, make one with the old tags
$entries = $database->get_one("SELECT COUNT(*) FROM tag_histories WHERE image_id = ?", array($image->id));
if($entries == 0){
$database->execute("
INSERT INTO tag_histories(image_id, tags, user_id, user_ip, date_set)
VALUES (?, ?, ?, ?, now())",
array($image->id, $old_tags, 1, '127.0.0.1')); // TODO: Pick appropriate user id
$entries++;
}
// add a history entry
$row = $database->execute("
INSERT INTO tag_histories(image_id, tags, user_id, user_ip, date_set)
VALUES (?, ?, ?, ?, now())",
array($image->id, $new_tags, $user->id, $_SERVER['REMOTE_ADDR']));
$entries++;
// if needed remove oldest one
if($allowed == -1) return;
$entries = $database->get_one("SELECT COUNT(*) FROM tag_histories WHERE image_id = ?", array($image->id));
if($entries > $allowed)
{
// TODO: Make these queries better

View File

@ -11,7 +11,7 @@ class taggerTheme extends Themelet {
// Initialization code
$base_href = $config->get_string('base_href');
// TODO: AJAX test and fallback.
$page->add_header("<script src='$base_href/ext/tagger/webtoolkit.drag.js' type='text/javascript'></script>");
$page->add_html_header("<script src='$base_href/ext/tagger/webtoolkit.drag.js' type='text/javascript'></script>");
$page->add_block(new Block(null,
"<script type='text/javascript'>Tagger.initialize("
.$event->get_image()->id.");</script>","main",1000));

View File

@ -93,6 +93,7 @@ class Image {
public static function by_random($tags=array()) {
assert(is_array($tags));
$max = Image::count_images($tags);
if ($max < 1) return null; // From Issue #22 - opened by HungryFeline on May 30, 2011.
$rand = mt_rand(0, $max-1);
$set = Image::find_images($rand, 1, $tags);
if(count($set) > 0) return $set[0];
@ -463,8 +464,8 @@ class Image {
*/
public function remove_image_only() {
log_info("core-image", "Removed Image File ({$this->hash})");
unlink($this->get_image_filename());
unlink($this->get_thumb_filename());
@unlink($this->get_image_filename());
@unlink($this->get_thumb_filename());
}
/**

View File

@ -108,7 +108,8 @@ class Page {
var $heading = "";
var $subheading = "";
var $quicknav = "";
var $headers = array();
var $html_headers = array();
var $http_headers = array();
var $blocks = array();
/** @publicsection */
@ -136,11 +137,19 @@ class Page {
/**
* Add a line to the HTML head section
*/
public function add_header($line, $position=50) {
while(isset($this->headers[$position])) $position++;
$this->headers[$position] = $line;
public function add_html_header($line, $position=50) {
while(isset($this->html_headers[$position])) $position++;
$this->html_headers[$position] = $line;
}
/**
* Add a http header to be sent to the client.
*/
public function add_http_header($line, $position=50) {
while(isset($this->http_headers[$position])) $position++;
$this->http_headers[$position] = $line;
}
/**
* Add a Block of data
*/
@ -157,15 +166,21 @@ class Page {
*/
public function display() {
global $page;
header("Content-type: {$this->type}");
header("Content-type: ".$this->type);
header("X-Powered-By: SCore-".SCORE_VERSION);
if (!headers_sent()) {
foreach($this->http_headers as $head){ header($head); }
} else {
print "Error: Headers have already been sent to the client.";
}
switch($this->mode) {
case "page":
header("Cache-control: no-cache");
usort($this->blocks, "blockcmp");
$this->add_auto_headers();
$this->add_auto_html_headers();
$layout = new Layout();
$layout->display_page($page);
break;
@ -185,29 +200,132 @@ class Page {
break;
}
}
protected function add_auto_headers() {
protected function add_auto_html_headers() {
$data_href = get_base_href();
foreach(glob("lib/*.css") as $css) {
$this->add_header("<link rel='stylesheet' href='$data_href/$css' type='text/css'>");
/* Attempt to cache the CSS & JavaScript files */
if ($this->add_cached_auto_html_headers() === FALSE) {
// caching failed, add all files to html_headers.
foreach(glob("lib/*.css") as $css) {
$this->add_html_header("<link rel='stylesheet' href='$data_href/$css' type='text/css'>");
}
$css_files = glob("ext/*/style.css");
if($css_files) {
foreach($css_files as $css_file) {
$this->add_html_header("<link rel='stylesheet' href='$data_href/$css_file' type='text/css'>");
}
}
foreach(glob("lib/*.js") as $js) {
$this->add_html_header("<script src='$data_href/$js' type='text/javascript'></script>");
}
$js_files = glob("ext/*/script.js");
if($js_files) {
foreach($js_files as $js_file) {
$this->add_html_header("<script src='$data_href/$js_file' type='text/javascript'></script>");
}
}
}
$css_files = glob("ext/*/style.css");
if($css_files) {
foreach($css_files as $css_file) {
$this->add_header("<link rel='stylesheet' href='$data_href/$css_file' type='text/css'>");
}
/*
This function caches the CSS and JavaScript files.
This is done to reduce the number of HTTP requests (recommended by
the Yahoo high-performance guidelines). It combines all of the CSS
and JavaScript files into one for each type, and stores them in
cached files to serve the client. Changes to the CSS or JavaScript
files are caught by taking the md5sum of the concatenated files.
*/
private function add_cached_auto_html_headers()
{
$cache_location = 'data/cache/';
$data_href = get_base_href();
if(!file_exists($cache_location)) {
if (!mkdir($cache_location, 0750, true)) {
return false; // failed to create directory
}
}
foreach(glob("lib/*.js") as $js) {
$this->add_header("<script src='$data_href/$js' type='text/javascript'></script>");
/* ----- CSS Files ----- */
// First get all the CSS from the lib directory
$data_1 = '';
$css_files = glob("lib/*.css");
if($css_files) {
foreach($css_files as $css_file) {
$data_1 .= file_get_contents($css_file);
}
// Can't directly cache the CSS files, as they might have relative locations to images, etc. in them.
// We have to adjust the URLs accordingly before saving the cached file.
$pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/';
$replace = 'url("../../lib/${1}")';
$data_1 = preg_replace($pattern, $replace, $data_1);
}
// Next get all the CSS from the extensions
$data_2 = '';
$css_files = glob("ext/*/style.css");
if($css_files) {
foreach($css_files as $css_file) {
$data_2 .= file_get_contents($css_file);
}
// Can't directly cache the CSS files, as they might have relative locations to images, etc. in them.
// We have to adjust the URLs accordingly before saving the cached file.
$pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/';
$replace = 'url("../../${1}")';
$data_2 = preg_replace($pattern, $replace, $data_2);
}
// Combine the two
$data = $data_1 . $data_2;
// compute the MD5 sum of the concatenated CSS files
$md5sum = md5($data);
if (!file_exists($cache_location.$md5sum.'.css')) {
// remove any old cached CSS files.
$mask = '*.css';
array_map( 'unlink', glob( $mask ) );
// output the combined file
if (file_put_contents($cache_location.$md5sum.'.css', $data, LOCK_EX) === FALSE) {
return false;
}
}
// tell the client where to get the css cache file
$this->add_html_header('<link rel="stylesheet" href="'.$data_href.'/'.$cache_location.$md5sum.'.css'.'" type="text/css">');
/* ----- JavaScript Files ----- */
$data = '';
$js_files = glob("lib/*.js");
if($js_files) {
foreach($js_files as $js_file) {
$data .= file_get_contents($js_file);
}
}
$js_files = glob("ext/*/script.js");
if($js_files) {
foreach($js_files as $js_file) {
$this->add_header("<script src='$data_href/$js_file' type='text/javascript'></script>");
$data .= file_get_contents($js_file);
}
}
// compute the MD5 sum of the concatenated JavaScript files
$md5sum = md5($data);
if (!file_exists($cache_location.$md5sum.'.js')) {
// remove any old cached js files.
$mask = '*.js';
array_map( 'unlink', glob( $mask ) );
// output the combined file
if (file_put_contents($cache_location.$md5sum.'.js', $data, LOCK_EX) === FALSE) {
return false;
}
}
// tell the client where to get the js cache file
$this->add_html_header('<script src="'.$data_href.'/'.$cache_location.$md5sum.'.js'.'" type="text/javascript"></script>');
return true;
}
}
?>

View File

@ -14,8 +14,9 @@ class Handle404 extends SimpleExtension {
// hax.
if($page->mode == "page" && (!isset($page->blocks) || $this->count_main($page->blocks) == 0)) {
$h_pagename = html_escape(implode('/', $event->args));
header("HTTP/1.0 404 Page Not Found");
log_debug("handle_404", "Hit 404: $h_pagename");
$page->add_http_header("HTTP/1.0 404 Page Not Found",5);
$page->set_title("404");
$page->set_heading("404 - No Handler Found");
$page->add_block(new NavBlock());

View File

@ -1,21 +1,27 @@
<?php
/*
* Name: Image Manager
* Author: Shish
* Author: Shish <webmaster@shishnet.org>
* Modified by: jgen <jgen.tech@gmail.com>
* Description: Handle the image database
* Visibility: admin
*/
/*
* ImageAdditionEvent:
* $user -- the user adding the image
* $image -- the image being added
*
* An image is being added to the database
/**
* An image is being added to the database.
*/
class ImageAdditionEvent extends Event {
var $user, $image;
/**
* Inserts a new image into the database with its associated
* information. Also calls TagSetEvent to set the tags for
* this new image.
*
* @sa TagSetEvent
* @param $user The user adding the image
* @param $image The new image to add.
*/
public function ImageAdditionEvent(User $user, Image $image) {
$this->image = $image;
$this->user = $user;
@ -30,34 +36,41 @@ class ImageAdditionException extends SCoreException {
}
}
/*
* ImageDeletionEvent:
* $image -- the image being deleted
*
* An image is being deleted. Used by things like tags
* and comments handlers to clean out related rows in
* their tables
/**
* An image is being deleted.
*/
class ImageDeletionEvent extends Event {
var $image;
/**
* Deletes an image.
* Used by things like tags and comments handlers to
* clean out related rows in their tables.
*
* @param $image The image being deleted
*/
public function ImageDeletionEvent(Image $image) {
$this->image = $image;
}
}
/*
* 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.
/**
* An image is being replaced.
*/
class ImageReplaceEvent extends Event {
var $id, $image;
/**
* Replaces an image.
* Updates an existing ID in the database to use a new image
* file, leaving the tags and such unchanged. Also removes
* the old image file and thumbnail from the disk.
*
* @param $id
* The ID of the image to replace
* @param $image
* The image object of the new image to use
*/
public function ImageReplaceEvent($id, Image $image) {
$this->id = $id;
$this->image = $image;
@ -72,15 +85,18 @@ class ImageReplaceException extends SCoreException {
}
}
/*
* ThumbnailGenerationEvent:
* Request a thumb be made for an image
/**
* Request a thumbnail be made for an image object.
*/
class ThumbnailGenerationEvent extends Event {
var $hash;
var $type;
var $hash, $type;
/**
* Request a thumbnail be made for an image object
*
* @param $hash The unique hash of the image
* @param $type The type of the image
*/
public function ThumbnailGenerationEvent($hash, $type) {
$this->hash = $hash;
$this->type = $type;
@ -95,8 +111,7 @@ class ThumbnailGenerationEvent extends Event {
* $image -- the image who's link is being parsed
*/
class ParseLinkTemplateEvent extends Event {
var $link, $original;
var $image;
var $link, $original, $image;
public function ParseLinkTemplateEvent($link, Image $image) {
$this->link = $link;
@ -110,9 +125,8 @@ class ParseLinkTemplateEvent extends Event {
}
/*
* A class to handle adding / getting / removing image
* files from the disk
/**
* A class to handle adding / getting / removing image files from the disk.
*/
class ImageIO extends SimpleExtension {
public function onInitExt($event) {
@ -124,11 +138,12 @@ class ImageIO extends SimpleExtension {
$config->set_default_string('thumb_convert_path', 'convert.exe');
$config->set_default_bool('image_show_meta', false);
$config->set_default_bool('jquery_confirm', true);
$config->set_default_bool('image_jquery_confirm', true);
$config->set_default_string('image_ilink', '');
$config->set_default_string('image_tlink', '');
$config->set_default_string('image_tip', '$tags // $size // $filesize');
$config->set_default_string('upload_collision_handler', 'error');
$config->set_default_int('image_expires', (60*60*24*365) ); // defaults to one year
}
public function onPageRequest($event) {
@ -172,9 +187,15 @@ class ImageIO extends SimpleExtension {
public function onImageAdminBlockBuilding($event) {
global $user;
global $config;
if($user->is_admin()) {
$event->add_part($this->theme->get_deleter_html($event->image->id));
}
/* In the future, could perhaps allow users to replace images that they own as well... */
if ($user->is_admin() && $config->get_bool("upload_replace")) {
$event->add_part($this->theme->get_replace_html($event->image->id));
}
}
public function onImageAddition($event) {
@ -200,6 +221,9 @@ class ImageIO extends SimpleExtension {
}
public function onUserPageBuilding($event) {
global $user;
global $config;
$u_id = url_escape($event->display_user->id);
$i_image_count = Image::count_images(array("user_id={$event->display_user->id}"));
$i_days_old = ((time() - strtotime($event->display_user->join_date)) / 86400) + 1;
@ -219,7 +243,17 @@ class ImageIO extends SimpleExtension {
if(!in_array("OS", $_SERVER) || $_SERVER["OS"] != 'Windows_NT') {
$sb->add_bool_option("image_show_meta", "<br>Show metadata: ");
}
$sb->add_bool_option("jquery_confirm", "<br>Confirm Delete with jQuery: ");
$sb->add_bool_option("image_jquery_confirm", "<br>Confirm Delete with jQuery: ");
$expires = array();
$expires['1 Minute'] = 60;
$expires['1 Hour'] = 3600;
$expires['1 Day'] = 86400;
$expires['1 Month (31 days)'] = 2678400; //(60*60*24*31)
$expires['1 Year'] = 31536000; // 365 days (60*60*24*365)
$expires['Never'] = 3153600000; // 100 years..
$sb->add_choice_option("image_expires", $expires, "<br>Image Expiration: ");
$event->panel->add_block($sb);
$thumbers = array();
@ -344,13 +378,18 @@ class ImageIO extends SimpleExtension {
}
$gmdate_mod = gmdate('D, d M Y H:i:s', filemtime($file)) . ' GMT';
// FIXME: should be $page->blah
if($if_modified_since == $gmdate_mod) {
header("HTTP/1.0 304 Not Modified");
$page->add_http_header("HTTP/1.0 304 Not Modified",3);
}
else {
header("Last-Modified: $gmdate_mod");
header("Expires: Fri, 2 Sep 2101 12:42:42 GMT"); // War was beginning
$page->add_http_header("Last-Modified: $gmdate_mod");
if ( $config->get_int("image_expires") ) {
$expires = date(DATE_RFC1123, time() + $config->get_int("image_expires"));
} else {
$expires = 'Fri, 2 Sep 2101 12:42:42 GMT'; // War was beginning
}
$page->add_http_header('Expires: '.$expires);
}
}
else {
@ -403,7 +442,7 @@ class ImageIO extends SimpleExtension {
id = :id
",
array(
"filename"=>$image_new->filename, "filesize"=>$image->filesize, "hash"=>$image->hash,
"filename"=>$image->filename, "filesize"=>$image->filesize, "hash"=>$image->hash,
"ext"=>$image->ext, "width"=>$image->width, "height"=>$image->height, "source"=>$image->source,
"id"=>$id
)

View File

@ -1,42 +1,46 @@
<?php
class ImageIOTheme {
/*
/**
* Display a link to delete an image
* (Added inline Javascript to confirm the deletion)
*
* $image_id = the image to delete
* @param $image_id The image to delete
*/
public function get_deleter_html($image_id) {
global $user;
global $config;
$i_image_id = int_escape($image_id);
if($config->get_bool("jquery_confirm")) {
if($config->get_bool("image_jquery_confirm")) {
$html = "
".make_form(make_link("image_admin/delete"),'POST',false,'delete_image')."
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='hidden' name='image_id' value='$image_id' />
<input type='submit' value='Delete' id='delete_image_submit' />
</form>
";
} else {
$html = "
".make_form(make_link("image_admin/delete"))."
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='hidden' name='image_id' value='$image_id' />
<input type='submit' value='Delete' onclick='return confirm(\"Delete the image?\");' />
</form>
";
}
if($config->get_bool("upload_replace") && $user->is_admin()) {
$html .= "
".make_form(make_link("image_admin/replace"))."
<input type='hidden' name='image_id' value='$i_image_id' />
<input type='submit' value='Replace' />
</form>
";
}
return $html;
}
/**
* Display link to replace the image
*
* @param $image_id The image to replace
*/
public function get_replace_html($image_id) {
$html = "
".make_form(make_link("image_admin/replace"))."
<input type='hidden' name='image_id' value='$image_id' />
<input type='submit' value='Replace' />
</form>";
return $html;
}
}

View File

@ -5,17 +5,19 @@
* Description: Allows people to upload files to the website
*/
/*
* DataUploadEvent:
* $user -- the user uploading the data
* $tmpname -- the temporary file used for upload
* $metadata -- info about the file, should contain at least "filename", "extension", "tags" and "source"
*
* Some data is being uploaded. Should be caught by a file handler.
/**
* Occurs when some data is being uploaded.
*/
class DataUploadEvent extends Event {
var $user, $tmpname, $metadata, $hash, $type, $image_id = -1;
/**
* Some data is being uploaded.
* This should be caught by a file handler.
* @param $user The user uploading the data.
* @param $tmpname The temporary file used for upload.
* @param $metadata Info about the file, should contain at least "filename", "extension", "tags" and "source".
*/
public function DataUploadEvent(User $user, $tmpname, $metadata) {
assert(file_exists($tmpname));
@ -34,6 +36,11 @@ class DataUploadEvent extends Event {
class UploadException extends SCoreException {}
/**
* Main upload class.
* All files that are uploaded to the site are handled through this class.
* This also includes transloaded files as well.
*/
class Upload implements Extension {
var $theme;
// event handling {{{
@ -107,6 +114,9 @@ class Upload implements Extension {
throw new UploadException("Can not upload more than one image for replacing.");
}
$source = isset($_POST['source']) ? $_POST['source'] : null;
$tags = ''; // Tags aren't changed when uploading. Set to null to stop PHP warnings.
if (count($_FILES)) {
foreach($_FILES as $file) {
$ok = $this->try_upload($file, $tags, $source, $image_id);
@ -273,7 +283,8 @@ class Upload implements Extension {
if($event->image_id == -1) {
throw new UploadException("File type not recognised");
}
header("X-Shimmie-Image-ID: ".int_escape($event->image_id));
//header("X-Shimmie-Image-ID: ".int_escape($event->image_id));
$page->add_http_header("X-Shimmie-Image-ID: ".int_escape($event->image_id));
}
catch(UploadException $ex) {
$this->theme->display_upload_error($page, "Error with ".html_escape($file['name']),

View File

@ -86,16 +86,16 @@ class UploadTheme extends Themelet {
<tr>
<td width='50'>File</td>
<td width='250'><input id='data0' name='data0' type='file'></td>
</tr>
";
if($tl_enabled) {
$upload_list .= "
<tr>
<td width='50'>URL</td>
<td width='250'><input id='url0' name='url0' type='text'></td>
</tr>
";
}
$upload_list .= "
</tr>
";
$max_size = $config->get_int('upload_size');
$max_kb = to_shorthand_int($max_size);
@ -103,7 +103,9 @@ class UploadTheme extends Themelet {
$image = Image::by_id($image_id);
$thumbnail = $this->build_thumb_html($image, null);
$html = "<p>Replacing Image ID ".$image_id."<br>Please note: You will have to refresh the image page, or empty your browser cache.</p>"
$html = "
<div style='clear:both;'></div>
<p>Replacing Image ID ".$image_id."<br>Please note: You will have to refresh the image page, or empty your browser cache.</p>"
.$thumbnail."<br>"
.make_form(make_link("upload/replace/".$image_id), "POST", $multipart=True)."
<input type='hidden' name='image_id' value='$image_id'>

View File

@ -10,11 +10,11 @@ class ViewImageTheme extends Themelet {
$metatags = str_replace(" ", ", ", html_escape($image->get_tag_list()));
$page->set_title("Image {$image->id}: ".html_escape($image->get_tag_list()));
$page->add_header("<meta name=\"keywords\" content=\"$metatags\">");
$page->add_header("<meta property=\"og:title\" content=\"$metatags\">");
$page->add_header("<meta property=\"og:type\" content=\"article\">");
$page->add_header("<meta property=\"og:image\" content=\"".make_http($image->get_thumb_link())."\">");
$page->add_header("<meta property=\"og:url\" content=\"".make_http(make_link("post/view/{$image->id}"))."\">");
$page->add_html_header("<meta name=\"keywords\" content=\"$metatags\">");
$page->add_html_header("<meta property=\"og:title\" content=\"$metatags\">");
$page->add_html_header("<meta property=\"og:type\" content=\"article\">");
$page->add_html_header("<meta property=\"og:image\" content=\"".make_http($image->get_thumb_link())."\">");
$page->add_html_header("<meta property=\"og:url\" content=\"".make_http(make_link("post/view/{$image->id}"))."\">");
$page->set_heading(html_escape($image->get_tag_list()));
$page->add_block(new Block("Navigation", $this->build_navigation($image), "left", 0));
$page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 10));

View File

@ -53,8 +53,8 @@ class Layout {
$header_html = "";
ksort($page->headers);
foreach($page->headers as $line) {
ksort($page->html_headers);
foreach($page->html_headers as $line) {
$header_html .= "\t\t$line\n";
}

View File

@ -10,7 +10,7 @@ class Themelet {
public function display_permission_denied(Page $page) {
header("HTTP/1.0 403 Permission Denied");
$page->add_http_header("HTTP/1.0 403 Permission Denied");
$this->display_error($page, "Permission Denied", "You do not have permission to access this page");
}

View File

@ -14,8 +14,8 @@ class Layout {
$contact_link = $config->get_string('contact_link');
$header_html = "";
ksort($page->headers);
foreach($page->headers as $line) {
ksort($page->html_headers);
foreach($page->html_headers as $line) {
$header_html .= "\t\t$line\n";
}

View File

@ -18,7 +18,7 @@ class Themelet {
* A specific, common error message
*/
public function display_permission_denied(Page $page) {
header("HTTP/1.0 403 Permission Denied");
$page->add_http_header("HTTP/1.0 403 Permission Denied");
$this->display_error($page, "Permission Denied", "You do not have permission to access this page");
}

View File

@ -14,8 +14,8 @@ class Layout {
$contact_link = $config->get_string('contact_link');
$header_html = "";
ksort($page->headers);
foreach($page->headers as $line) {
ksort($page->html_headers);
foreach($page->html_headers as $line) {
$header_html .= "\t\t$line\n";
}

View File

@ -18,7 +18,7 @@ class Themelet {
* A specific, common error message
*/
public function display_permission_denied(Page $page) {
header("HTTP/1.0 403 Permission Denied");
$page->add_http_header("HTTP/1.0 403 Permission Denied");
$this->display_error($page, "Permission Denied", "You do not have permission to access this page");
}

View File

@ -9,8 +9,8 @@ class Layout {
$contact_link = $config->get_string('contact_link');
$header_html = "";
ksort($page->headers);
foreach($page->headers as $line) {
ksort($page->html_headers);
foreach($page->html_headers as $line) {
$header_html .= "\t\t$line\n";
}

View File

@ -20,7 +20,7 @@ class Layout {
$contact_link = $config->get_string('contact_link');
$header_html = "";
foreach($page->headers as $line) {
foreach($page->html_headers as $line) {
$header_html .= "\t\t$line\n";
}

View File

@ -18,7 +18,7 @@ class Themelet {
* A specific, common error message
*/
public function display_permission_denied(Page $page) {
header("HTTP/1.0 403 Permission Denied");
$page->add_http_header("HTTP/1.0 403 Permission Denied");
$this->display_error($page, "Permission Denied", "You do not have permission to access this page");
}

View File

@ -9,8 +9,8 @@ class Layout {
$contact_link = $config->get_string('contact_link');
$header_html = "";
ksort($page->headers);
foreach($page->headers as $line) {
ksort($page->html_headers);
foreach($page->html_headers as $line) {
$header_html .= "\t\t$line\n";
}

View File

@ -16,7 +16,7 @@ class Themelet {
* A specific, common error message
*/
public function display_permission_denied(Page $page) {
header("HTTP/1.0 403 Permission Denied");
$page->add_http_header("HTTP/1.0 403 Permission Denied");
$this->display_error($page, "Permission Denied", "You do not have permission to access this page");
}

View File

@ -14,7 +14,7 @@ class Layout {
$contact_link = $config->get_string('contact_link');
$header_html = "";
foreach($page->headers as $line) {
foreach($page->html_headers as $line) {
$header_html .= "\t\t$line\n";
}

View File

@ -18,7 +18,7 @@ class Themelet {
* A specific, common error message
*/
public function display_permission_denied(Page $page) {
header("HTTP/1.0 403 Permission Denied");
$page->add_http_header("HTTP/1.0 403 Permission Denied");
$this->display_error($page, "Permission Denied", "You do not have permission to access this page");
}