summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcopypaste <admin@8chan.co>2014-04-27 15:48:47 +0200
committerczaks <marcin@6irc.net>2014-04-27 15:48:47 +0200
commitc483e1258cb5d168812a6e509e982a172f6c36c6 (patch)
treebe6324a26d75b43b2f4e1f017661b50b89aa8d2b
parent7a04150b04d953f457c3fddf4bc198597f7e6470 (diff)
multiimage posting
-rw-r--r--inc/api.php49
-rw-r--r--inc/config.php46
-rw-r--r--inc/display.php21
-rw-r--r--inc/functions.php89
-rw-r--r--inc/lib/Twig/Extensions/Extension/Tinyboard.php6
-rw-r--r--inc/mod/pages.php6
-rw-r--r--install.php25
-rw-r--r--js/multi_image.js30
-rw-r--r--post.php224
-rw-r--r--stylesheets/style.css3
-rw-r--r--templates/main.js1
-rw-r--r--templates/post/fileinfo.html38
-rw-r--r--templates/post_reply.html34
-rw-r--r--templates/post_thread.html34
-rw-r--r--templates/posts.sql12
-rw-r--r--templates/themes/catalog/theme.php5
-rw-r--r--templates/themes/recent/theme.php12
-rw-r--r--templates/themes/ukko/theme.php4
18 files changed, 366 insertions, 273 deletions
diff --git a/inc/api.php b/inc/api.php
index 3337c613..a8ae9eed 100644
--- a/inc/api.php
+++ b/inc/api.php
@@ -26,12 +26,6 @@ class Api {
'trip' => 'trip',
'capcode' => 'capcode',
'time' => 'time',
- 'thumbheight' => 'tn_w',
- 'thumbwidth' => 'tn_h',
- 'fileheight' => 'w',
- 'filewidth' => 'h',
- 'filesize' => 'fsize',
- 'filename' => 'filename',
'omitted' => 'omitted_posts',
'omitted_images' => 'omitted_images',
'replies' => 'replies',
@@ -46,6 +40,15 @@ class Api {
'bump' => 'last_modified'
);
+ $this->fileFields = array(
+ 'thumbheight' => 'tn_w',
+ 'thumbwidth' => 'tn_h',
+ 'height' => 'w',
+ 'width' => 'h',
+ 'size' => 'fsize',
+ 'file' => 'filename',
+ );
+
if (isset($config['api']['extra_fields']) && gettype($config['api']['extra_fields']) == 'array'){
$this->postFields = array_merge($this->postFields, $config['api']['extra_fields']);
}
@@ -67,30 +70,26 @@ class Api {
'last_modified' => 1
);
- private function translatePost($post, $threadsPage = false) {
- $apiPost = array();
- $fields = $threadsPage ? $this->threadsPageFields : $this->postFields;
+ private function translateFields($fields, $object, &$apiPost) {
foreach ($fields as $local => $translated) {
- if (!isset($post->$local))
+ if (!isset($object->$local))
continue;
$toInt = isset(self::$ints[$translated]);
- $val = $post->$local;
+ $val = $object->$local;
if ($val !== null && $val !== '') {
$apiPost[$translated] = $toInt ? (int) $val : $val;
}
}
+ }
- if ($threadsPage) return $apiPost;
+ private function translatePost($post, $threadsPage = false) {
+ $apiPost = array();
+ $fields = $threadsPage ? $this->threadsPageFields : $this->postFields;
+ $this->translateFields($fields, $post, $apiPost);
- if (isset($post->filename)) {
- $dotPos = strrpos($post->filename, '.');
- $apiPost['filename'] = substr($post->filename, 0, $dotPos);
- $apiPost['ext'] = substr($post->filename, $dotPos);
- $dotPos = strrpos($post->file, '.');
- $apiPost['tim'] = substr($post->file, 0, $dotPos);
- }
+ if ($threadsPage) return $apiPost;
// Handle country field
if (isset($post->body_nomarkup) && $this->config['country_flags']) {
@@ -104,6 +103,18 @@ class Api {
}
}
+ // Handle files
+ // Note: 4chan only supports one file, so only the first file is taken into account for 4chan-compatible API.
+ if (isset($post->files) && $post->files && !$threadsPage) {
+ $file = $post->files[0];
+ $this->translateFields($this->fileFields, $file, $apiPost);
+ $dotPos = strrpos($file->file, '.');
+ $apiPost['filename'] = substr($file->file, 0, $dotPos);
+ $apiPost['ext'] = substr($file->file, $dotPos);
+ $dotPos = strrpos($file->file, '.');
+ $apiPost['tim'] = substr($file->file, 0, $dotPos);
+ }
+
return $apiPost;
}
diff --git a/inc/config.php b/inc/config.php
index a4d1c6d5..6ec08a09 100644
--- a/inc/config.php
+++ b/inc/config.php
@@ -607,6 +607,17 @@
* Image settings
* ====================
*/
+ // Maximum number of images allowed. Increasing this number enabled multi image.
+ // If you make it more than 1, make sure to enable the below script for the post form to change.
+ // $config['additional_javascript'][] = 'js/multi_image.js';
+ $config['max_images'] = 1;
+
+ // Method to use for determing the max filesize.
+ // "split" means that your max filesize is split between the images. For example, if your max filesize
+ // is 2MB, the filesizes of all files must add up to 2MB for it to work.
+ // "each" means that each file can be 2MB, so if your max_images is 3, each post could contain 6MB of
+ // images. "split" is recommended.
+ $config['multiimage_method'] = 'split';
// For resizing, maximum thumbnail dimensions.
$config['thumb_width'] = 255;
@@ -628,22 +639,22 @@
/*
* Thumbnailing method:
*
- * 'gd' PHP GD (default). Only handles the most basic image formats (GIF, JPEG, PNG).
- * GD is a prerequisite for Tinyboard no matter what method you choose.
+ * 'gd' PHP GD (default). Only handles the most basic image formats (GIF, JPEG, PNG).
+ * GD is a prerequisite for Tinyboard no matter what method you choose.
*
- * 'imagick' PHP's ImageMagick bindings. Fast and efficient, supporting many image formats.
- * A few minor bugs. http://pecl.php.net/package/imagick
+ * 'imagick' PHP's ImageMagick bindings. Fast and efficient, supporting many image formats.
+ * A few minor bugs. http://pecl.php.net/package/imagick
*
- * 'convert' The command line version of ImageMagick (`convert`). Fixes most of the bugs in
- * PHP Imagick. `convert` produces the best still thumbnails and is highly recommended.
+ * 'convert' The command line version of ImageMagick (`convert`). Fixes most of the bugs in
+ * PHP Imagick. `convert` produces the best still thumbnails and is highly recommended.
*
- * 'gm' GraphicsMagick (`gm`) is a fork of ImageMagick with many improvements. It is more
- * efficient and gets thumbnailing done using fewer resources.
+ * 'gm' GraphicsMagick (`gm`) is a fork of ImageMagick with many improvements. It is more
+ * efficient and gets thumbnailing done using fewer resources.
*
* 'convert+gifscale'
- * OR 'gm+gifsicle' Same as above, with the exception of using `gifsicle` (command line application)
- * instead of `convert` for resizing GIFs. It's faster and resulting animated
- * thumbnails have less artifacts than if resized with ImageMagick.
+ * OR 'gm+gifsicle' Same as above, with the exception of using `gifsicle` (command line application)
+ * instead of `convert` for resizing GIFs. It's faster and resulting animated
+ * thumbnails have less artifacts than if resized with ImageMagick.
*/
$config['thumb_method'] = 'gd';
// $config['thumb_method'] = 'convert';
@@ -693,7 +704,7 @@
// An alternative function for generating image filenames, instead of the default UNIX timestamp.
// $config['filename_func'] = function($post) {
- // return sprintf("%s", time() . substr(microtime(), 2, 3));
+ // return sprintf("%s", time() . substr(microtime(), 2, 3));
// };
// Thumbnail to use for the non-image file uploads.
@@ -986,6 +997,7 @@
$config['error']['toolong_body'] = _('The body was too long.');
$config['error']['tooshort_body'] = _('The body was too short or empty.');
$config['error']['noimage'] = _('You must upload an image.');
+ $config['error']['toomanyimages'] = _('You have attempted to upload too many images!');
$config['error']['nomove'] = _('The server failed to handle your upload.');
$config['error']['fileext'] = _('Unsupported image format.');
$config['error']['noboard'] = _('Invalid board!');
@@ -1444,16 +1456,16 @@
$config['search']['enable'] = false;
// Maximal number of queries per IP address per minutes
- $config['search']['queries_per_minutes'] = Array(15, 2);
+ $config['search']['queries_per_minutes'] = Array(15, 2);
// Global maximal number of queries per minutes
- $config['search']['queries_per_minutes_all'] = Array(50, 2);
+ $config['search']['queries_per_minutes_all'] = Array(50, 2);
// Limit of search results
- $config['search']['search_limit'] = 100;
-
+ $config['search']['search_limit'] = 100;
+
// Boards for searching
- //$config['search']['boards'] = array('a', 'b', 'c', 'd', 'e');
+ //$config['search']['boards'] = array('a', 'b', 'c', 'd', 'e');
/*
* ====================
diff --git a/inc/display.php b/inc/display.php
index f7fe1620..0ae0ac05 100644
--- a/inc/display.php
+++ b/inc/display.php
@@ -94,7 +94,7 @@ function error($message, $priority = true, $debug_stuff = false) {
// Return the bad request header, necessary for AJAX posts
// czaks: is it really so? the ajax errors only work when this is commented out
- // better yet use it when ajax is disabled
+ // better yet use it when ajax is disabled
if (!isset ($_POST['json_response'])) {
header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
}
@@ -338,6 +338,9 @@ class Post {
foreach ($post as $key => $value) {
$this->{$key} = $value;
}
+
+ if (isset($this->files))
+ $this->files = json_decode($this->files);
$this->subject = utf8tohtml($this->subject);
$this->name = utf8tohtml($this->name);
@@ -396,7 +399,7 @@ class Post {
$built .= ' <a title="'._('Ban & Delete').'" href="?/' . $board['dir'] . 'ban&amp;delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>';
// Delete file (keep post)
- if (!empty($this->file) && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
+ if (!empty($this->files) && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_deletefile'], _('Delete file'), _('Are you sure you want to delete this file?'), $board['dir'] . 'deletefile/' . $this->id);
// Spoiler file (keep post)
@@ -418,9 +421,6 @@ class Post {
return $built;
}
- public function ratio() {
- return fraction($this->filewidth, $this->fileheight, ':');
- }
public function build($index=false) {
global $board, $config;
@@ -439,6 +439,9 @@ class Thread {
$this->{$key} = $value;
}
+ if (isset($this->files))
+ $this->files = json_decode($this->files);
+
$this->subject = utf8tohtml($this->subject);
$this->name = utf8tohtml($this->name);
$this->mod = $mod;
@@ -477,7 +480,7 @@ class Thread {
$this->posts[] = $post;
}
public function postCount() {
- return count($this->posts) + $this->omitted;
+ return count($this->posts) + $this->omitted;
}
public function postControls() {
global $board, $config;
@@ -506,7 +509,7 @@ class Thread {
$built .= ' <a title="'._('Ban & Delete').'" href="?/' . $board['dir'] . 'ban&amp;delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>';
// Delete file (keep post)
- if (!empty($this->file) && $this->file != 'deleted' && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
+ if (!empty($this->files) && $this->files[0]->file != 'deleted' && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
$built .= ' ' . secure_link_confirm($config['mod']['link_deletefile'], _('Delete file'), _('Are you sure you want to delete this file?'), $board['dir'] . 'deletefile/' . $this->id);
// Spoiler file (keep post)
@@ -546,10 +549,6 @@ class Thread {
return $built;
}
- public function ratio() {
- return fraction($this->filewidth, $this->fileheight, ':');
- }
-
public function build($index=false, $isnoko50=false) {
global $board, $config, $debug;
diff --git a/inc/functions.php b/inc/functions.php
index 820ee838..1db2b7f3 100644
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -96,9 +96,9 @@ function loadConfig() {
$configstr = file_get_contents('inc/instance-config.php');
- if (isset($board['dir']) && file_exists($board['dir'] . '/config.php')) {
- $configstr .= file_get_contents($board['dir'] . '/config.php');
- }
+ if (isset($board['dir']) && file_exists($board['dir'] . '/config.php')) {
+ $configstr .= file_get_contents($board['dir'] . '/config.php');
+ }
$matches = array();
preg_match_all('/[^\/*#]\$config\s*\[\s*[\'"]locale[\'"]\s*\]\s*=\s*([\'"])(.*?)\1/', $configstr, $matches);
if ($matches && isset ($matches[2]) && $matches[2]) {
@@ -859,7 +859,7 @@ function insertFloodPost(array $post) {
function post(array $post) {
global $pdo, $board;
- $query = prepare(sprintf("INSERT INTO ``posts_%s`` VALUES ( NULL, :thread, :subject, :email, :name, :trip, :capcode, :body, :body_nomarkup, :time, :time, :thumb, :thumbwidth, :thumbheight, :file, :width, :height, :filesize, :filename, :filehash, :password, :ip, :sticky, :locked, 0, :embed)", $board['uri']));
+ $query = prepare(sprintf("INSERT INTO ``posts_%s`` VALUES ( NULL, :thread, :subject, :email, :name, :trip, :capcode, :body, :body_nomarkup, :time, :time, :files, :num_files, :filehash, :password, :ip, :sticky, :locked, 0, :embed)", $board['uri']));
// Basic stuff
if (!empty($post['subject'])) {
@@ -919,31 +919,12 @@ function post(array $post) {
}
if ($post['has_file']) {
- $query->bindValue(':thumb', $post['thumb']);
- $query->bindValue(':thumbwidth', $post['thumbwidth'], PDO::PARAM_INT);
- $query->bindValue(':thumbheight', $post['thumbheight'], PDO::PARAM_INT);
- $query->bindValue(':file', $post['file']);
-
- if (isset($post['width'], $post['height'])) {
- $query->bindValue(':width', $post['width'], PDO::PARAM_INT);
- $query->bindValue(':height', $post['height'], PDO::PARAM_INT);
- } else {
- $query->bindValue(':width', null, PDO::PARAM_NULL);
- $query->bindValue(':height', null, PDO::PARAM_NULL);
- }
-
- $query->bindValue(':filesize', $post['filesize'], PDO::PARAM_INT);
- $query->bindValue(':filename', $post['filename']);
+ $query->bindValue(':files', json_encode($post['files']));
+ $query->bindValue(':num_files', $post['num_files']);
$query->bindValue(':filehash', $post['filehash']);
} else {
- $query->bindValue(':thumb', null, PDO::PARAM_NULL);
- $query->bindValue(':thumbwidth', null, PDO::PARAM_NULL);
- $query->bindValue(':thumbheight', null, PDO::PARAM_NULL);
- $query->bindValue(':file', null, PDO::PARAM_NULL);
- $query->bindValue(':width', null, PDO::PARAM_NULL);
- $query->bindValue(':height', null, PDO::PARAM_NULL);
- $query->bindValue(':filesize', null, PDO::PARAM_NULL);
- $query->bindValue(':filename', null, PDO::PARAM_NULL);
+ $query->bindValue(':files', null, PDO::PARAM_NULL);
+ $query->bindValue(':num_files', 0);
$query->bindValue(':filehash', null, PDO::PARAM_NULL);
}
@@ -974,28 +955,31 @@ function bumpThread($id) {
function deleteFile($id, $remove_entirely_if_already=true) {
global $board, $config;
- $query = prepare(sprintf("SELECT `thread`,`thumb`,`file` FROM ``posts_%s`` WHERE `id` = :id LIMIT 1", $board['uri']));
+ $query = prepare(sprintf("SELECT `thread`, `files` FROM ``posts_%s`` WHERE `id` = :id LIMIT 1", $board['uri']));
$query->bindValue(':id', $id, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
if (!$post = $query->fetch(PDO::FETCH_ASSOC))
error($config['error']['invalidpost']);
+ $files = json_decode($post['files']);
- if ($post['file'] == 'deleted' && !$post['thread'])
+ if ($files[0]->file == 'deleted' && !$post['thread'])
return; // Can't delete OP's image completely.
- $query = prepare(sprintf("UPDATE ``posts_%s`` SET `thumb` = NULL, `thumbwidth` = NULL, `thumbheight` = NULL, `filewidth` = NULL, `fileheight` = NULL, `filesize` = NULL, `filename` = NULL, `filehash` = NULL, `file` = :file WHERE `id` = :id", $board['uri']));
- if ($post['file'] == 'deleted' && $remove_entirely_if_already) {
+ $query = prepare(sprintf("UPDATE ``posts_%s`` SET `files` = :file WHERE `id` = :id", $board['uri']));
+ if ($files[0]->file == 'deleted' && $remove_entirely_if_already) {
// Already deleted; remove file fully
$query->bindValue(':file', null, PDO::PARAM_NULL);
} else {
- // Delete thumbnail
- file_unlink($board['dir'] . $config['dir']['thumb'] . $post['thumb']);
+ foreach ($files as $i => $file) {
+ // Delete thumbnail
+ file_unlink($board['dir'] . $config['dir']['thumb'] . $file->thumb);
- // Delete file
- file_unlink($board['dir'] . $config['dir']['img'] . $post['file']);
+ // Delete file
+ file_unlink($board['dir'] . $config['dir']['img'] . $file->file);
+ }
// Set file to 'deleted'
- $query->bindValue(':file', 'deleted', PDO::PARAM_INT);
+ $query->bindValue(':file', '[{"file":"deleted"}]', PDO::PARAM_STR);
}
$query->bindValue(':id', $id, PDO::PARAM_INT);
@@ -1035,7 +1019,7 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true) {
global $board, $config;
// Select post and replies (if thread) in one query
- $query = prepare(sprintf("SELECT `id`,`thread`,`thumb`,`file` FROM ``posts_%s`` WHERE `id` = :id OR `thread` = :id", $board['uri']));
+ $query = prepare(sprintf("SELECT `id`,`thread`,`files` FROM ``posts_%s`` WHERE `id` = :id OR `thread` = :id", $board['uri']));
$query->bindValue(':id', $id, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
@@ -1065,13 +1049,12 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true) {
// Rebuild thread
$rebuild = &$post['thread'];
}
- if ($post['thumb']) {
- // Delete thumbnail
- file_unlink($board['dir'] . $config['dir']['thumb'] . $post['thumb']);
- }
- if ($post['file']) {
+ if ($post['files']) {
// Delete file
- file_unlink($board['dir'] . $config['dir']['img'] . $post['file']);
+ foreach (json_decode($post['files']) as $i => $f) {
+ file_unlink($board['dir'] . $config['dir']['img'] . $f->file);
+ file_unlink($board['dir'] . $config['dir']['thumb'] . $f->thumb);
+ }
}
$ids[] = (int)$post['id'];
@@ -1188,8 +1171,8 @@ function index($page, $mod=false) {
$num_images = 0;
foreach ($replies as $po) {
- if ($po['file'])
- $num_images++;
+ if ($po['num_files'])
+ $num_images+=$po['num_files'];
$thread->add(new Post($po, $mod ? '?/' : $config['root'], $mod));
}
@@ -1347,7 +1330,7 @@ function checkRobot($body) {
// Returns an associative array with 'replies' and 'images' keys
function numPosts($id) {
global $board;
- $query = prepare(sprintf("SELECT COUNT(*) AS `replies`, COUNT(NULLIF(`file`, 0)) AS `images` FROM ``posts_%s`` WHERE `thread` = :thread", $board['uri'], $board['uri']));
+ $query = prepare(sprintf("SELECT COUNT(*) AS `replies`, SUM(`num_files`) AS `images` FROM ``posts_%s`` WHERE `thread` = :thread", $board['uri'], $board['uri']));
$query->bindValue(':thread', $id, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
@@ -1905,7 +1888,7 @@ function markup(&$body, $track_cites = false) {
}
// replace tabs with 8 spaces
- $body = str_replace("\t", ' ', $body);
+ $body = str_replace("\t", ' ', $body);
return $tracked_cites;
}
@@ -2232,13 +2215,15 @@ function getPostByHashInThread($hash, $thread) {
}
function undoImage(array $post) {
- if (!$post['has_file'])
+ if (!$post['has_file'] || !isset($post['files']))
return;
- if (isset($post['file_path']))
- file_unlink($post['file_path']);
- if (isset($post['thumb_path']))
- file_unlink($post['thumb_path']);
+ foreach ($post['files'] as $key => $file) {
+ if (isset($file['file_path']))
+ file_unlink($file['file_path']);
+ if (isset($file['thumb_path']))
+ file_unlink($file['thumb_path']);
+ }
}
function rDNS($ip_addr) {
diff --git a/inc/lib/Twig/Extensions/Extension/Tinyboard.php b/inc/lib/Twig/Extensions/Extension/Tinyboard.php
index 727d5d2c..4063bfd4 100644
--- a/inc/lib/Twig/Extensions/Extension/Tinyboard.php
+++ b/inc/lib/Twig/Extensions/Extension/Tinyboard.php
@@ -25,7 +25,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
new Twig_SimpleFilter('until', 'until'),
new Twig_SimpleFilter('push', 'twig_push_filter'),
new Twig_SimpleFilter('bidi_cleanup', 'bidi_cleanup'),
- new Twig_SimpleFilter('addslashes', 'addslashes')
+ new Twig_SimpleFilter('addslashes', 'addslashes'),
);
}
@@ -42,6 +42,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
new Twig_SimpleFunction('timezone', 'twig_timezone_function'),
new Twig_SimpleFunction('hiddenInputs', 'hiddenInputs'),
new Twig_SimpleFunction('hiddenInputsHash', 'hiddenInputsHash'),
+ new Twig_SimpleFunction('ratio', 'twig_ratio_function')
);
}
@@ -100,3 +101,6 @@ function twig_truncate_filter($value, $length = 30, $preserve = false, $separato
return $value;
}
+function twig_ratio_function($w, $h) {
+ return fraction($w, $h, ':');
+}
diff --git a/inc/mod/pages.php b/inc/mod/pages.php
index a247e35c..89bc6e41 100644
--- a/inc/mod/pages.php
+++ b/inc/mod/pages.php
@@ -1538,10 +1538,10 @@ function mod_deletefile($board, $post) {
function mod_spoiler_image($board, $post) {
global $config, $mod;
-
+
if (!openBoard($board))
error($config['error']['noboard']);
-
+
if (!hasPermission($config['mod']['spoilerimage'], $board))
error($config['error']['noaccess']);
@@ -1572,7 +1572,7 @@ function mod_spoiler_image($board, $post) {
// Rebuild themes
rebuildThemes('post-delete', $board);
-
+
// Redirect
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
}
diff --git a/install.php b/install.php
index 16ef9fcb..4a5a54cb 100644
--- a/install.php
+++ b/install.php
@@ -1,7 +1,7 @@
<?php
// Installation/upgrade file
-define('VERSION', '4.4.98');
+define('VERSION', '4.9.90');
require 'inc/functions.php';
@@ -260,7 +260,7 @@ if (file_exists($config['has_installed'])) {
$_query->execute() or error(db_error($_query));
}
}
- case 'v0.9.6-dev-9':
+ case 'v0.9.6-dev-9':
case 'v0.9.6-dev-9 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.3</a>':
case 'v0.9.6-dev-9 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.4-gold</a>':
case 'v0.9.6-dev-9 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.5-gold</a>':
@@ -521,6 +521,14 @@ if (file_exists($config['has_installed'])) {
case '4.4.98-pre':
if (!$twig) load_twig();
$twig->clearCacheFiles();
+ case '4.4.98':
+ foreach ($boards as &$board) {
+ query(sprintf('ALTER TABLE ``posts_%s`` ADD `files` text DEFAULT NULL AFTER `bump`;', $board['uri'])) or error(db_error());
+ query(sprintf('ALTER TABLE ``posts_%s`` ADD `num_files` int(11) DEFAULT 0 AFTER `files`;', $board['uri'])) or error(db_error());
+ query(sprintf('UPDATE ``posts_%s`` SET `files` = CONCAT(\'[{"file":"\',`filename`,\'", "size":"\',`filesize`,\'", "width":"\',`filewidth`,\'","height":"\',`fileheight`,\'","thumbwidth":"\',`thumbwidth`,\'","thumbheight":"\',`thumbheight`,\'", "file_path":"%s\/src\/\',`filename`,\'","thumb_path":"%s\/thumb\/\',`filename`,\'"}]\') WHERE `file` IS NOT NULL', $board['uri'], $board['uri'], $board['uri'])) or error(db_error());
+ query(sprintf('ALTER TABLE ``posts_%s`` DROP COLUMN `thumb`, DROP COLUMN `thumbwidth`, DROP COLUMN `thumbheight`, DROP COLUMN `file`, DROP COLUMN `fileheight`, DROP COLUMN `filesize`, DROP COLUMN `filename`', $board['uri'])) or error(db_error());
+ query(sprintf('ALTER TABLE ``posts_%s`` REBUILD', $board['uri'])) or error(db_error());
+ }
case false:
// TODO: enhance Tinyboard -> vichan upgrade path.
query("CREATE TABLE IF NOT EXISTS ``search_queries`` ( `ip` varchar(39) NOT NULL, `time` int(11) NOT NULL, `query` text NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8;") or error(db_error());
@@ -586,7 +594,7 @@ if ($step == 0) {
'required' => false
)
);
-
+
$tests = array(
array(
'category' => 'PHP',
@@ -680,6 +688,13 @@ if ($step == 0) {
'message' => '(Optional) `gifsicle` was not found or executable; you may not use `convert+gifsicle` for better animated GIF thumbnailing.',
),
array(
+ 'category' => 'Image processing',
+ 'name' => '`md5sum` (quick file hashing)',
+ 'result' => $can_exec && shell_exec('echo "vichan" | md5sum') == "141225c362da02b5c359c45b665168de -\n",
+ 'required' => false,
+ 'message' => '(Optional) `md5sum` was not found or executable; file hashing for multiple images will be slower.',
+ ),
+ array(
'category' => 'File permissions',
'name' => getcwd(),
'result' => is_writable('.'),
@@ -833,9 +848,9 @@ if ($step == 0) {
}
file_write($config['has_installed'], VERSION);
- if (!file_unlink(__FILE__)) {
+ /*if (!file_unlink(__FILE__)) {
$page['body'] .= '<div class="ban"><h2>Delete install.php!</h2><p>I couldn\'t remove <strong>install.php</strong>. You will have to remove it manually.</p></div>';
- }
+ }*/
}
echo Element('page.html', $page);
diff --git a/js/multi_image.js b/js/multi_image.js
new file mode 100644
index 00000000..cb2f2ccf
--- /dev/null
+++ b/js/multi_image.js
@@ -0,0 +1,30 @@
+/*
+ * multi-image.js - Add support for multiple images to the post form
+ *
+ * Copyright (c) 2014 Fredrick Brennan <admin@8chan.co>
+ *
+ * Usage:
+ * $config['max_images'] = 3;
+ * $config['additional_javascript'][] = 'js/jquery.min.js';
+ * $config['additional_javascript'][] = 'js/multi-image.js';
+ */
+
+function multi_image() {
+ $('input[type=file]').after('<a href="#" class="add_image">+</a>');
+
+ $(document).on('click', 'a.add_image', function(e) {
+ e.preventDefault();
+ $('#upload_url').remove();
+
+ var images_len = $('input[type=file]').length;
+
+ if (!(images_len >= max_images)) {
+ $('.add_image').after('<br/><input type="file" name="file'+(images_len+1)+'" id="upload_file'+(images_len+1)+'">');
+ if (typeof setup_form !== 'undefined') setup_form($('form[name="post"]'));
+ }
+ })
+}
+
+if (active_page == 'thread' || active_page == 'index' && max_images > 1) {
+ $(document).ready(multi_image);
+}
diff --git a/post.php b/post.php
index 91abe7e6..3420f7f4 100644
--- a/post.php
+++ b/post.php
@@ -150,7 +150,7 @@ if (isset($_POST['delete'])) {
if (!isset($_POST['body'], $_POST['board']))
error($config['error']['bot']);
- $post = array('board' => $_POST['board']);
+ $post = array('board' => $_POST['board'], 'files' => array());
// Check if board exists
if (!openBoard($post['board']))
@@ -178,7 +178,7 @@ if (isset($_POST['delete'])) {
$post['op'] = true;
if (!(($post['op'] && $_POST['post'] == $config['button_newtopic']) ||
- (!$post['op'] && $_POST['post'] == $config['button_reply'])))
+ (!$post['op'] && $_POST['post'] == $config['button_reply'])))
error($config['error']['bot']);
// Check the referrer
@@ -328,21 +328,12 @@ if (isset($_POST['delete'])) {
);
}
- // Check for a file
- if ($post['op'] && !isset($post['no_longer_require_an_image_for_op'])) {
- if (!isset($_FILES['file']['tmp_name']) || $_FILES['file']['tmp_name'] == '' && $config['force_image_op'])
- error($config['error']['noimage']);
- }
-
$post['name'] = $_POST['name'] != '' ? $_POST['name'] : $config['anonymous'];
$post['subject'] = $_POST['subject'];
$post['email'] = str_replace(' ', '%20', htmlspecialchars($_POST['email']));
$post['body'] = $_POST['body'];
$post['password'] = $_POST['password'];
- $post['has_file'] = !isset($post['embed']) && (($post['op'] && !isset($post['no_longer_require_an_image_for_op']) && $config['force_image_op']) || (isset($_FILES['file']) && $_FILES['file']['tmp_name'] != ''));
-
- if ($post['has_file'])
- $post['filename'] = urldecode(get_magic_quotes_gpc() ? stripslashes($_FILES['file']['name']) : $_FILES['file']['name']);
+ $post['has_file'] = (!isset($post['embed']) && (($post['op'] && !isset($post['no_longer_require_an_image_for_op']) && $config['force_image_op']) || !empty($_FILES)));
if (!($post['has_file'] || isset($post['embed'])) || (($post['op'] && $config['force_body_op']) || (!$post['op'] && $config['force_body']))) {
$stripped_whitespace = preg_replace('/[\s]/u', '', $post['body']);
@@ -367,6 +358,22 @@ if (isset($_POST['delete'])) {
}
if ($post['has_file']) {
+ // Determine size sanity
+ $size = 0;
+ if ($config['multiimage_method'] == 'split') {
+ foreach ($_FILES as $key => $file) {
+ $size += $file['size'];
+ }
+ } elseif ($config['multiimage_method'] == 'each') {
+ foreach ($_FILES as $key => $file) {
+ if ($file['size'] > $size) {
+ $size = $file['size'];
+ }
+ }
+ } else {
+ error(_('Unrecognized file size determination method.'));
+ }
+
$size = $_FILES['file']['size'];
if ($size > $config['max_filesize'])
error(sprintf3($config['error']['filesize'], array(
@@ -374,6 +381,7 @@ if (isset($_POST['delete'])) {
'filesz' => number_format($size),
'maxsz' => number_format($config['max_filesize'])
)));
+ $post['filesize'] = $size;
}
@@ -409,16 +417,39 @@ if (isset($_POST['delete'])) {
} else $noko = $config['always_noko'];
if ($post['has_file']) {
- $post['extension'] = strtolower(mb_substr($post['filename'], mb_strrpos($post['filename'], '.') + 1));
- if (isset($config['filename_func']))
- $post['file_id'] = $config['filename_func']($post);
- else
- $post['file_id'] = time() . substr(microtime(), 2, 3);
-
- $post['file'] = $board['dir'] . $config['dir']['img'] . $post['file_id'] . '.' . $post['extension'];
- $post['thumb'] = $board['dir'] . $config['dir']['thumb'] . $post['file_id'] . '.' . ($config['thumb_ext'] ? $config['thumb_ext'] : $post['extension']);
+ $i = 0;
+ foreach ($_FILES as $key => $file) {
+ if ($file['size'] && $file['tmp_name']) {
+ $file['filename'] = urldecode(get_magic_quotes_gpc() ? stripslashes($file['name']) : $file['name']);
+ $file['extension'] = strtolower(mb_substr($file['filename'], mb_strrpos($file['filename'], '.') + 1));
+ if (isset($config['filename_func']))
+ $file['file_id'] = $config['filename_func']($file);
+ else
+ $file['file_id'] = time() . substr(microtime(), 2, 3);
+
+ if (sizeof($_FILES) > 1)
+ $file['file_id'] .= "-$i";
+
+ $file['file'] = $board['dir'] . $config['dir']['img'] . $file['file_id'] . '.' . $file['extension'];
+ $file['thumb'] = $board['dir'] . $config['dir']['thumb'] . $file['file_id'] . '.' . ($config['thumb_ext'] ? $config['thumb_ext'] : $file['extension']);
+ $post['files'][] = $file;
+ $i++;
+ }
+ }
}
-
+
+ if (empty($post['files'])) $post['has_file'] = false;
+
+ // Check for a file
+ if ($post['op'] && !isset($post['no_longer_require_an_image_for_op'])) {
+ if (!$post['has_file'] && $config['force_image_op'])
+ error($config['error']['noimage']);
+ }
+
+ // Check for too many files
+ if (sizeof($post['files']) > $config['max_images'])
+ error($config['error']['toomanyimages']);
+
if ($config['strip_combining_chars']) {
$post['name'] = strip_combining_chars($post['name']);
$post['email'] = strip_combining_chars($post['email']);
@@ -475,7 +506,7 @@ if (isset($_POST['delete'])) {
$user_flag = $_POST['user_flag'];
if (!isset($config['user_flags'][$user_flag]))
- error('Invalid flag selection!');
+ error(_('Invalid flag selection!'));
$flag_alt = isset($user_flag_alt) ? $user_flag_alt : $config['user_flags'][$user_flag];
@@ -505,21 +536,38 @@ if (isset($_POST['delete'])) {
if ($post['has_file']) {
- if (!in_array($post['extension'], $config['allowed_ext']) && !in_array($post['extension'], $config['allowed_ext_files']))
- error($config['error']['unknownext']);
-
- $is_an_image = !in_array($post['extension'], $config['allowed_ext_files']);
-
- // Truncate filename if it is too long
- $post['filename'] = mb_substr($post['filename'], 0, $config['max_filename_len']);
-
- $upload = $_FILES['file']['tmp_name'];
-
- if (!is_readable($upload))
- error($config['error']['nomove']);
+ foreach ($post['files'] as $key => &$file) {
+ if (!in_array($file['extension'], $config['allowed_ext']) && !in_array($file['extension'], $config['allowed_ext_files']))
+ error($config['error']['unknownext']);
+
+ $file['is_an_image'] = !in_array($file['extension'], $config['allowed_ext_files']);
+
+ // Truncate filename if it is too long
+ $file['filename'] = mb_substr($file['filename'], 0, $config['max_filename_len']);
+
+ if (!isset($filenames)) {
+ $filenames = escapeshellarg($file['tmp_name']);
+ } else {
+ $filenames .= (' ' . escapeshellarg($file['tmp_name']));
+ }
+ $upload = $file['tmp_name'];
+
+ if (!is_readable($upload))
+ error($config['error']['nomove']);
+ }
- $post['filehash'] = md5_file($upload);
- $post['filesize'] = filesize($upload);
+ if ($output = shell_exec_error("cat $filenames | md5sum")) {
+ $hash = explode(' ', $output)[0];
+ $post['filehash'] = $hash;
+ } elseif ($config['max_images'] === 1) {
+ $post['filehash'] = md5_file($upload);
+ } else {
+ $str_to_hash = '';
+ foreach (explode(' ', $filenames) as $i => $f) {
+ $str_to_hash .= file_get_contents($f);
+ }
+ $post['filehash'] = md5($str_to_hash);
+ }
}
if (!hasPermission($config['mod']['bypass_filters'], $board['uri'])) {
@@ -529,7 +577,8 @@ if (isset($_POST['delete'])) {
}
if ($post['has_file']) {
- if ($is_an_image && $config['ie_mime_type_detection'] !== false) {
+ foreach ($post['files'] as $key => &$file) {
+ if ($file['is_an_image'] && $config['ie_mime_type_detection'] !== false) {
// Check IE MIME type detection XSS exploit
$buffer = file_get_contents($upload, null, null, null, 255);
if (preg_match($config['ie_mime_type_detection'], $buffer)) {
@@ -540,7 +589,7 @@ if (isset($_POST['delete'])) {
require_once 'inc/image.php';
// find dimensions of an image using GD
- if (!$size = @getimagesize($upload)) {
+ if (!$size = @getimagesize($file['tmp_name'])) {
error($config['error']['invalidimg']);
}
if ($size[0] > $config['max_width'] || $size[1] > $config['max_height']) {
@@ -548,93 +597,93 @@ if (isset($_POST['delete'])) {
}
- if ($config['convert_auto_orient'] && ($post['extension'] == 'jpg' || $post['extension'] == 'jpeg')) {
+ if ($config['convert_auto_orient'] && ($file['extension'] == 'jpg' || $file['extension'] == 'jpeg')) {
// The following code corrects the image orientation.
// Currently only works with the 'convert' option selected but it could easily be expanded to work with the rest if you can be bothered.
- if (!($config['redraw_image'] || (($config['strip_exif'] && !$config['use_exiftool']) && ($post['extension'] == 'jpg' || $post['extension'] == 'jpeg')))) {
+ if (!($config['redraw_image'] || (($config['strip_exif'] && !$config['use_exiftool']) && ($file['extension'] == 'jpg' || $file['extension'] == 'jpeg')))) {
if (in_array($config['thumb_method'], array('convert', 'convert+gifsicle', 'gm', 'gm+gifsicle'))) {
- $exif = @exif_read_data($upload);
+ $exif = @exif_read_data($file['tmp_name']);
$gm = in_array($config['thumb_method'], array('gm', 'gm+gifsicle'));
if (isset($exif['Orientation']) && $exif['Orientation'] != 1) {
if ($config['convert_manual_orient']) {
$error = shell_exec_error(($gm ? 'gm ' : '') . 'convert ' .
- escapeshellarg($upload) . ' ' .
+ escapeshellarg($file['tmp_name']) . ' ' .
ImageConvert::jpeg_exif_orientation(false, $exif) . ' ' .
($config['strip_exif'] ? '+profile "*"' :
($config['use_exiftool'] ? '' : '+profile "*"')
) . ' ' .
- escapeshellarg($upload));
+ escapeshellarg($file['tmp_name']));
if ($config['use_exiftool'] && !$config['strip_exif']) {
if ($exiftool_error = shell_exec_error(
'exiftool -overwrite_original -q -q -orientation=1 -n ' .
- escapeshellarg($upload)))
- error('exiftool failed!', null, $exiftool_error);
+ escapeshellarg($file['tmp_name'])))
+ error(_('exiftool failed!'), null, $exiftool_error);
} else {
// TODO: Find another way to remove the Orientation tag from the EXIF profile
// without needing `exiftool`.
}
} else {
$error = shell_exec_error(($gm ? 'gm ' : '') . 'convert ' .
- escapeshellarg($upload) . ' -auto-orient ' . escapeshellarg($upload));
+ escapeshellarg($file['tmp_name']) . ' -auto-orient ' . escapeshellarg($upload));
}
if ($error)
- error('Could not auto-orient image!', null, $error);
- $size = @getimagesize($upload);
+ error(_('Could not auto-orient image!'), null, $error);
+ $size = @getimagesize($file['tmp_name']);
if ($config['strip_exif'])
- $post['exif_stripped'] = true;
+ $file['exif_stripped'] = true;
}
}
}
}
// create image object
- $image = new Image($upload, $post['extension'], $size);
+ $image = new Image($file['tmp_name'], $file['extension'], $size);
if ($image->size->width > $config['max_width'] || $image->size->height > $config['max_height']) {
$image->delete();
error($config['error']['maxsize']);
}
- $post['width'] = $image->size->width;
- $post['height'] = $image->size->height;
+ $file['width'] = $image->size->width;
+ $file['height'] = $image->size->height;
if ($config['spoiler_images'] && isset($_POST['spoiler'])) {
- $post['thumb'] = 'spoiler';
+ $file['thumb'] = 'spoiler';
$size = @getimagesize($config['spoiler_image']);
- $post['thumbwidth'] = $size[0];
- $post['thumbheight'] = $size[1];
+ $file['thumbwidth'] = $size[0];
+ $file['thumbheight'] = $size[1];
} elseif ($config['minimum_copy_resize'] &&
$image->size->width <= $config['thumb_width'] &&
$image->size->height <= $config['thumb_height'] &&
- $post['extension'] == ($config['thumb_ext'] ? $config['thumb_ext'] : $post['extension'])) {
+ $file['extension'] == ($config['thumb_ext'] ? $config['thumb_ext'] : $file['extension'])) {
// Copy, because there's nothing to resize
- copy($upload, $post['thumb']);
+ copy($file['tmp_name'], $file['thumb']);
- $post['thumbwidth'] = $image->size->width;
- $post['thumbheight'] = $image->size->height;
+ $file['thumbwidth'] = $image->size->width;
+ $file['thumbheight'] = $image->size->height;
} else {
$thumb = $image->resize(
- $config['thumb_ext'] ? $config['thumb_ext'] : $post['extension'],
+ $config['thumb_ext'] ? $config['thumb_ext'] : $file['extension'],
$post['op'] ? $config['thumb_op_width'] : $config['thumb_width'],
$post['op'] ? $config['thumb_op_height'] : $config['thumb_height']
);
- $thumb->to($post['thumb']);
+ $thumb->to($file['thumb']);
- $post['thumbwidth'] = $thumb->width;
- $post['thumbheight'] = $thumb->height;
+ $file['thumbwidth'] = $thumb->width;
+ $file['thumbheight'] = $thumb->height;
$thumb->_destroy();
}
- if ($config['redraw_image'] || (!@$post['exif_stripped'] && $config['strip_exif'] && ($post['extension'] == 'jpg' || $post['extension'] == 'jpeg'))) {
+ if ($config['redraw_image'] || (!@$file['exif_stripped'] && $config['strip_exif'] && ($file['extension'] == 'jpg' || $file['extension'] == 'jpeg'))) {
if (!$config['redraw_image'] && $config['use_exiftool']) {
if($error = shell_exec_error('exiftool -overwrite_original -ignoreMinorErrors -q -q -all= ' .
- escapeshellarg($upload)))
- error('Could not strip EXIF metadata!', null, $error);
+ escapeshellarg($file['tmp_name'])))
+ error(_('Could not strip EXIF metadata!', null, $error));
} else {
- $image->to($post['file']);
+ $image->to($file['file']);
$dont_copy_file = true;
}
}
@@ -642,26 +691,25 @@ if (isset($_POST['delete'])) {
} else {
// not an image
//copy($config['file_thumb'], $post['thumb']);
- $post['thumb'] = 'file';
+ $file['thumb'] = 'file';
$size = @getimagesize(sprintf($config['file_thumb'],
- isset($config['file_icons'][$post['extension']]) ?
- $config['file_icons'][$post['extension']] : $config['file_icons']['default']));
- $post['thumbwidth'] = $size[0];
- $post['thumbheight'] = $size[1];
+ isset($config['file_icons'][$file['extension']]) ?
+ $config['file_icons'][$file['extension']] : $config['file_icons']['default']));
+ $file['thumbwidth'] = $size[0];
+ $file['thumbheight'] = $size[1];
}
if (!isset($dont_copy_file) || !$dont_copy_file) {
- if (isset($post['file_tmp'])) {
- if (!@rename($upload, $post['file']))
+ if (isset($file['file_tmp'])) {
+ if (!@rename($file['tmp_name'], $file['file']))
error($config['error']['nomove']);
- chmod($post['file'], 0644);
- } elseif (!@move_uploaded_file($upload, $post['file']))
+ chmod($file['file'], 0644);
+ } elseif (!@move_uploaded_file($file['tmp_name'], $file['file']))
error($config['error']['nomove']);
}
- }
-
- if ($post['has_file']) {
+ }
+
if ($config['image_reject_repost']) {
if ($p = getPostByHash($post['filehash'])) {
undoImage($post);
@@ -689,7 +737,7 @@ if (isset($_POST['delete'])) {
));
}
}
- }
+ }
if (!hasPermission($config['mod']['postunoriginal'], $board['uri']) && $config['robot_enable'] && checkRobot($post['body_nomarkup'])) {
undoImage($post);
@@ -702,11 +750,13 @@ if (isset($_POST['delete'])) {
// Remove board directories before inserting them into the database.
if ($post['has_file']) {
- $post['file_path'] = $post['file'];
- $post['thumb_path'] = $post['thumb'];
- $post['file'] = mb_substr($post['file'], mb_strlen($board['dir'] . $config['dir']['img']));
- if ($is_an_image && $post['thumb'] != 'spoiler')
- $post['thumb'] = mb_substr($post['thumb'], mb_strlen($board['dir'] . $config['dir']['thumb']));
+ foreach ($post['files'] as $key => &$file) {
+ $file['file_path'] = $file['file'];
+ $file['thumb_path'] = $file['thumb'];
+ $file['file'] = mb_substr($file['file'], mb_strlen($board['dir'] . $config['dir']['img']));
+ if ($file['is_an_image'] && $file['thumb'] != 'spoiler')
+ $file['thumb'] = mb_substr($file['thumb'], mb_strlen($board['dir'] . $config['dir']['thumb']));
+ }
}
$post = (object)$post;
@@ -715,6 +765,10 @@ if (isset($_POST['delete'])) {
error($error);
}
$post = (array)$post;
+
+ if ($post['files'])
+ $post['files'] = $post['files'];
+ $post['num_files'] = sizeof($post['files']);
$post['id'] = $id = post($post);
diff --git a/stylesheets/style.css b/stylesheets/style.css
index b167dbb0..df873e68 100644
--- a/stylesheets/style.css
+++ b/stylesheets/style.css
@@ -109,6 +109,9 @@ form table tr td div label {
.unimportant, .unimportant * {
font-size: 10px;
}
+.file {
+ float: left;
+}
p.fileinfo {
display: block;
margin: 0;
diff --git a/templates/main.js b/templates/main.js
index 7796565c..953d8849 100644
--- a/templates/main.js
+++ b/templates/main.js
@@ -291,6 +291,7 @@ function ready() {
{% endraw %}
var post_date = "{{ config.post_date }}";
+var max_images = {{ config.max_images }};
onready(init);
diff --git a/templates/post/fileinfo.html b/templates/post/fileinfo.html
new file mode 100644
index 00000000..2136169b
--- /dev/null
+++ b/templates/post/fileinfo.html
@@ -0,0 +1,38 @@
+ {% if post.embed %}
+ {{ post.embed }}
+ {% else %}
+ <div class="files">
+ {% for file in post.files %}
+ <div class="file">
+ {% if file.file == 'deleted' %}
+ <img class="post-image deleted" src="{{ config.image_deleted }}" alt="" />
+ {% else %}
+ <p class="fileinfo">File: <a href="{{ config.uri_img }}{{ file.file }}">{{ file.file }}</a> <span class="unimportant">
+ (
+ {% if file.thumb == 'spoiler' %}
+ {% trans %}Spoiler Image{% endtrans %},
+ {% endif %}
+ {{ file.size|filesize }}
+ {% if file.width and file.height %}
+ , {{ file.width}}x{{ file.height }}
+ {% if config.show_ratio %}
+ , {{ ratio(file.width, file.height) }}
+ {% endif %}
+ {% endif %}
+ {% if config.show_filename and file.filename %}
+ ,
+ {% if file.filename|length > config.max_filename_display %}
+ <span class="postfilename" title="{{ file.filename|e }}">{{ file.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
+ {% else %}
+ <span class="postfilename">{{ file.filename|e|bidi_cleanup }}</span>
+ {% endif %}
+ {% endif %}
+ {% include "post/image_identification.html" %}
+ )
+ </span></p>
+ {% include "post/image.html" with {'post':file} %}
+ {% endif %}
+</div>
+ {% endfor %}
+</div>
+ {% endif %}
diff --git a/templates/post_reply.html b/templates/post_reply.html
index 90ac5065..3d860872 100644
--- a/templates/post_reply.html
+++ b/templates/post_reply.html
@@ -1,7 +1,6 @@
{% filter remove_whitespace %}
{# tabs and new lines will be ignored #}
<div class="post reply" id="reply_{{ post.id }}">
-
<p class="intro"{% if not index %} id="{{ post.id }}"{% endif %}>
<input type="checkbox" class="delete" name="delete_{{ post.id }}" id="delete_{{ post.id }}" />
<label for="delete_{{ post.id }}">
@@ -18,38 +17,9 @@
{{ post.id }}
</a>
</p>
- {% if post.embed %}
- {{ post.embed }}
- {% elseif post.file == 'deleted' %}
- <img class="post-image deleted" src="{{ config.image_deleted }}" alt="" />
- {% elseif post.file and post.file %}
- <p class="fileinfo">File: <a href="{{ config.uri_img }}{{ post.file }}">{{ post.file }}</a> <span class="unimportant">
- (
- {% if post.thumb == 'spoiler' %}
- {% trans %}Spoiler Image{% endtrans %},
- {% endif %}
- {{ post.filesize|filesize }}
- {% if post.filewidth and post.fileheight %}
- , {{ post.filewidth}}x{{ post.fileheight }}
- {% if config.show_ratio %}
- , {{ post.ratio }}
- {% endif %}
- {% endif %}
- {% if config.show_filename and post.filename %}
- ,
- {% if post.filename|length > config.max_filename_display %}
- <span class="postfilename" title="{{ post.filename|e }}">{{ post.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
- {% else %}
- <span class="postfilename">{{ post.filename|e|bidi_cleanup }}</span>
- {% endif %}
- {% endif %}
- {% include "post/image_identification.html" %}
- )
- </span></p>
- {% include "post/image.html" %}
- {% endif %}
+ {% include 'post/fileinfo.html' %}
{{ post.postControls }}
- <div class="body">
+ <div class="body" {% if post.files|length > 1 %}style="clear:both"{% endif %}>
{% endfilter %}{% if index %}{{ post.body|truncate_body(post.link) }}{% else %}{{ post.body }}{% endif %}{% filter remove_whitespace %}
{% if post.modifiers['ban message'] %}
{{ config.mod.ban_message|sprintf(post.modifiers['ban message']) }}
diff --git a/templates/post_thread.html b/templates/post_thread.html
index f74427e4..a5bf8e08 100644
--- a/templates/post_thread.html
+++ b/templates/post_thread.html
@@ -2,38 +2,8 @@
{# tabs and new lines will be ignored #}
<div id="thread_{{ post.id }}" data-board="{{ board.uri }}">
-
-{% if post.embed %}
- {{ post.embed }}
-{% elseif post.file == 'deleted' %}
- <img class="post-image deleted" src="{{ config.image_deleted }}" alt="" />
-{% elseif post.file and post.file %}
- <p class="fileinfo">{% trans %}File:{% endtrans %} <a href="{{ config.uri_img }}{{ post.file }}">{{ post.file }}</a> <span class="unimportant">
- (
- {% if post.thumb == 'spoiler' %}
- {% trans %}Spoiler Image{% endtrans %},
- {% endif %}
- {{ post.filesize|filesize }}
- {% if post.filewidth and post.fileheight %}
- , {{ post.filewidth}}x{{ post.fileheight }}
- {% if config.show_ratio %}
- , {{ post.ratio }}
- {% endif %}
- {% endif %}
- {% if config.show_filename and post.filename %}
- ,
- {% if post.filename|length > config.max_filename_display %}
- <span class="postfilename" title="{{ post.filename|e }}">{{ post.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
- {% else %}
- <span class="postfilename">{{ post.filename|e|bidi_cleanup }}</span>
- {% endif %}
- {% endif %}
- {% include "post/image_identification.html" %}
- )
- </span></p>
- {% include "post/image.html" %}
-{% endif %}
-<div class="post op"><p class="intro"{% if not index %} id="{{ post.id }}"{% endif %}>
+{% include 'post/fileinfo.html' %}
+<div class="post op" {%if post.num_files > 1%}style='clear:both'{%endif%}><p class="intro"{% if not index %} id="{{ post.id }}"{% endif %}>
<input type="checkbox" class="delete" name="delete_{{ post.id }}" id="delete_{{ post.id }}" />
<label for="delete_{{ post.id }}">
{% include 'post/subject.html' %}
diff --git a/templates/posts.sql b/templates/posts.sql
index c1f491f2..9a47c6ad 100644
--- a/templates/posts.sql
+++ b/templates/posts.sql
@@ -10,14 +10,8 @@ CREATE TABLE IF NOT EXISTS ``posts_{{ board }}`` (
`body_nomarkup` text,
`time` int(11) NOT NULL,
`bump` int(11) DEFAULT NULL,
- `thumb` varchar(255) DEFAULT NULL,
- `thumbwidth` int(11) DEFAULT NULL,
- `thumbheight` int(11) DEFAULT NULL,
- `file` varchar(255) DEFAULT NULL,
- `filewidth` int(11) DEFAULT NULL,
- `fileheight` int(11) DEFAULT NULL,
- `filesize` int(11) DEFAULT NULL,
- `filename` text,
+ `files` text DEFAULT NULL,
+ `num_files` int(11) DEFAULT 0,
`filehash` text CHARACTER SET ascii,
`password` varchar(20) DEFAULT NULL,
`ip` varchar(39) CHARACTER SET ascii NOT NULL,
@@ -32,4 +26,4 @@ CREATE TABLE IF NOT EXISTS ``posts_{{ board }}`` (
KEY `ip` (`ip`),
KEY `list_threads` (`thread`, `sticky`, `bump`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ;
- \ No newline at end of file
+
diff --git a/templates/themes/catalog/theme.php b/templates/themes/catalog/theme.php
index d3a837ca..1f42b8d1 100644
--- a/templates/themes/catalog/theme.php
+++ b/templates/themes/catalog/theme.php
@@ -40,7 +40,10 @@
while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
$post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], ($post['thread'] ? $post['thread'] : $post['id']));
$post['board_name'] = $board['name'];
- $post['file'] = $config['uri_thumb'] . $post['thumb'];
+ if (isset($post['files']))
+ $files = json_decode($post['files']);
+ if ($files[0]->file == 'deleted') continue;
+ $post['file'] = $config['uri_thumb'] . $files[0]->thumb;
$recent_posts[] = $post;
}
diff --git a/templates/themes/recent/theme.php b/templates/themes/recent/theme.php
index 26a9a69b..842ab9ac 100644
--- a/templates/themes/recent/theme.php
+++ b/templates/themes/recent/theme.php
@@ -42,7 +42,7 @@
foreach ($boards as &$_board) {
if (in_array($_board['uri'], $this->excluded))
continue;
- $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` WHERE `file` IS NOT NULL AND `file` != 'deleted' AND `thumb` != 'spoiler' UNION ALL ", $_board['uri'], $_board['uri']);
+ $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` WHERE `files` IS NOT NULL UNION ALL ", $_board['uri'], $_board['uri']);
}
$query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int)$settings['limit_images'], $query);
@@ -54,10 +54,14 @@
while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
openBoard($post['board']);
+ if (isset($post['files']))
+ $files = json_decode($post['files']);
+
+ if ($files[0]->file == 'deleted') continue;
// board settings won't be available in the template file, so generate links now
$post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], ($post['thread'] ? $post['thread'] : $post['id'])) . '#' . $post['id'];
- $post['src'] = $config['uri_thumb'] . $post['thumb'];
+ if ($files) $post['src'] = $config['uri_thumb'] . $files[0]->thumb;
$recent_images[] = $post;
}
@@ -105,7 +109,7 @@
$stats['unique_posters'] = number_format($query->fetchColumn());
// Active content
- $query = 'SELECT SUM(`filesize`) FROM (';
+ /*$query = 'SELECT SUM(`filesize`) FROM (';
foreach ($boards as &$_board) {
if (in_array($_board['uri'], $this->excluded))
continue;
@@ -113,7 +117,7 @@
}
$query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query);
$query = query($query) or error(db_error());
- $stats['active_content'] = $query->fetchColumn();
+ $stats['active_content'] = $query->fetchColumn();*/
return Element('themes/recent/recent.html', Array(
'settings' => $settings,
diff --git a/templates/themes/ukko/theme.php b/templates/themes/ukko/theme.php
index 1ca00014..88b0c4a4 100644
--- a/templates/themes/ukko/theme.php
+++ b/templates/themes/ukko/theme.php
@@ -51,14 +51,14 @@
$num_images = 0;
while ($po = $posts->fetch()) {
- if ($po['file'])
+ if ($po['files'])
$num_images++;
$thread->add(new Post($po, $mod ? '?/' : $config['root'], $mod));
}
if ($posts->rowCount() == ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) {
- $ct = prepare(sprintf("SELECT COUNT(`id`) as `num` FROM ``posts_%s`` WHERE `thread` = :thread UNION ALL SELECT COUNT(`id`) FROM ``posts_%s`` WHERE `file` IS NOT NULL AND `thread` = :thread", $post['board'], $post['board']));
+ $ct = prepare(sprintf("SELECT COUNT(`id`) as `num` FROM ``posts_%s`` WHERE `thread` = :thread UNION ALL SELECT COUNT(`id`) FROM ``posts_%s`` WHERE `files` IS NOT NULL AND `thread` = :thread", $post['board'], $post['board']));
$ct->bindValue(':thread', $post['id'], PDO::PARAM_INT);
$ct->execute() or error(db_error($count));