summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--inc/config.php30
-rw-r--r--inc/functions.php27
-rw-r--r--inc/image.php70
-rw-r--r--post.php23
4 files changed, 117 insertions, 33 deletions
diff --git a/inc/config.php b/inc/config.php
index 4742fca9..8350ad63 100644
--- a/inc/config.php
+++ b/inc/config.php
@@ -63,6 +63,10 @@
// Use `host` via shell_exec() to lookup hostnames, avoiding query timeouts. May not work on your system.
// Requires safe_mode to be disabled.
$config['dns_system'] = false;
+
+ // When executing most command-line tools (such as `convert` for ImageMagick image processing), add this
+ // to the environment path (seperated by :).
+ $config['shell_path'] = '/usr/local/bin';
/*
* ====================
@@ -488,7 +492,11 @@
* '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+gifsicle' Same as above, with the exception of using `gifsicle` (command line application)
+ * '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.
*/
@@ -497,10 +505,24 @@
// Command-line options passed to ImageMagick when using `convert` for thumbnailing. Don't touch the
// placement of "%s" and "%d".
- $config['convert_args'] = '-background transparent %s -strip -thumbnail %dx%d -quality 65';
+ $config['convert_args'] = '-size %dx%d %s -thumbnail %dx%d +profile "*" %s';
// Strip EXIF metadata from JPEG files.
$config['strip_exif'] = false;
+ // Use the command-line `exiftool` tool to strip EXIF metadata without decompressing/recompressing JPEGs.
+ // Ignored when $config['redraw_image'] is true.
+ $config['strip_with_exiftool'] = false;
+
+ // Redraw the image to strip any excess data (commonly ZIP archives) WARNING: This might strip the
+ // animation of GIFs, depending on the chosen thumbnailing method. It also requires recompressing
+ // the image, so more processing power is required.
+ $config['redraw_image'] = false;
+
+ // Automatically correct the orientation of JPEG files using -auto-orient in `convert`. This only works
+ // when `convert` or `gm` is selected for thumbnailing. Again, requires more processing power because
+ // this basically does the same thing as $config['redraw_image']. (If $config['redraw_image'] is enabled,
+ // this value doesn't matter as $config['redraw_image'] attempts to correct orientation too.)
+ $config['convert_auto_orient'] = false;
// Regular expression to check for an XSS exploit with IE 6 and 7. To disable, set to false.
// Details: https://github.com/savetheinternet/Tinyboard/issues/20
@@ -563,10 +585,6 @@
// Display image identification links using regex.info/exif, TinEye and Google Images.
$config['image_identification'] = false;
- // Redraw the image to strip any excess data (commonly ZIP archives) WARNING: This might strip the
- // animation of GIFs, depending on the chosen thumbnailing method.
- $config['redraw_image'] = false;
-
/*
* ====================
* Board settings
diff --git a/inc/functions.php b/inc/functions.php
index 7740c8f7..4c3450f3 100644
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -80,7 +80,7 @@ function loadConfig() {
if ($config['debug']) {
if (!isset($debug)) {
- $debug = array('sql' => array(), 'purge' => array(), 'cached' => array(), 'write' => array());
+ $debug = array('sql' => array(), 'exec' => array(), 'purge' => array(), 'cached' => array(), 'write' => array());
$debug['start'] = microtime(true);
}
}
@@ -849,7 +849,7 @@ function bumpThread($id) {
if ($config['try_smarter'])
$build_pages[] = thread_find_page($id);
-
+
$query = prepare(sprintf("UPDATE ``posts_%s`` SET `bump` = :time WHERE `id` = :id AND `thread` IS NULL", $board['uri']));
$query->bindValue(':time', time(), PDO::PARAM_INT);
$query->bindValue(':id', $id, PDO::PARAM_INT);
@@ -1289,7 +1289,7 @@ function buildIndex() {
for ($page = 1; $page <= $config['max_pages']; $page++) {
$filename = $board['dir'] . ($page == 1 ? $config['file_index'] : sprintf($config['file_page'], $page));
-
+
if ($config['try_smarter'] && isset($build_pages) && count($build_pages) && !in_array($page, $build_pages) && is_file($filename))
continue;
$content = index($page);
@@ -1959,3 +1959,24 @@ function DNS($host) {
return $ip_addr;
}
+
+function shell_exec_error($command) {
+ global $config, $debug;
+
+ if ($config['debug'])
+ $start = microtime(true);
+
+ $return = trim(shell_exec('PATH="' . escapeshellcmd($config['shell_path']) . ':$PATH";' . $command . ' 2>&1 && echo "TB_SUCCESS"'));
+ $return = preg_replace('/TB_SUCCESS$/', '', $return);
+
+ if ($config['debug']) {
+ $time = round((microtime(true) - $start) * 1000, 2) . 'ms';
+ $debug['exec'][] = array(
+ 'command' => $command,
+ 'time' => '~' . $time,
+ 'response' => $return ? $return : null
+ );
+ }
+
+ return $return === 'TB_SUCCESS' ? false : $return;
+}
diff --git a/inc/image.php b/inc/image.php
index 88f735dd..92e74277 100644
--- a/inc/image.php
+++ b/inc/image.php
@@ -11,7 +11,7 @@ if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
class Image {
public $src, $format, $image, $size;
- public function __construct($src, $format = false) {
+ public function __construct($src, $format = false, $size = false) {
global $config;
$this->src = $src;
@@ -19,7 +19,7 @@ class Image {
if ($config['thumb_method'] == 'imagick') {
$classname = 'ImageImagick';
- } elseif ($config['thumb_method'] == 'convert' || $config['thumb_method'] == 'convert+gifsicle') {
+ } elseif (in_array($config['thumb_method'], array('convert', 'convert+gifsicle', 'gm', 'gm+gifsicle'))) {
$classname = 'ImageConvert';
} else {
$classname = 'Image' . strtoupper($this->format);
@@ -28,7 +28,7 @@ class Image {
}
}
- $this->image = new $classname($this);
+ $this->image = new $classname($this, $size);
if (!$this->image->valid()) {
$this->delete();
@@ -44,8 +44,6 @@ class Image {
public function resize($extension, $max_width, $max_height) {
global $config;
-
- $gifsicle = false;
if ($config['thumb_method'] == 'imagick') {
$classname = 'ImageImagick';
@@ -54,6 +52,13 @@ class Image {
} elseif ($config['thumb_method'] == 'convert+gifsicle') {
$classname = 'ImageConvert';
$gifsicle = true;
+ } elseif ($config['thumb_method'] == 'gm') {
+ $classname = 'ImageConvert';
+ $gm = true;
+ } elseif ($config['thumb_method'] == 'gm+gifsicle') {
+ $classname = 'ImageConvert';
+ $gm = true;
+ $gifsicle = true;
} else {
$classname = 'Image' . strtoupper($extension);
if (!class_exists($classname)) {
@@ -81,7 +86,6 @@ class Image {
$height = $max_height;
}
- $thumb->gifsicle = $gifsicle;
$thumb->_resize($this->image->image, $width, $height);
return $thumb;
@@ -118,10 +122,15 @@ class ImageBase extends ImageGD {
return (bool)$this->image;
}
- public function __construct($img) {
+ public function __construct($img, $size = false) {
if (method_exists($this, 'init'))
$this->init();
+ if ($size && $size[0] > 0 && $size[1] > 0) {
+ $this->width = $size[0];
+ $this->height = $size[1];
+ }
+
if ($img !== false) {
$this->src = $img->src;
$this->from();
@@ -227,15 +236,24 @@ class ImageImagick extends ImageBase {
class ImageConvert extends ImageBase {
- public $width, $height, $temp, $gifsicle;
+ public $width, $height, $temp, $gm = false, $gifsicle = false;
public function init() {
global $config;
+ if ($config['thumb_method'] == 'gm' || $config['thumb_method'] == 'gm+gifsicle')
+ $this->gm = true;
+ if ($config['thumb_method'] == 'convert+gifsicle' || $config['thumb_method'] == 'gm+gifsicle')
+ $this->gifsicle = true;
+
$this->temp = false;
}
- public function from() {
- $size = trim(shell_exec('identify -format "%w %h" ' . escapeshellarg($this->src . '[0]')));
+ public function from() {
+ if ($this->width > 0 && $this->height > 0) {
+ $this->image = true;
+ return;
+ }
+ $size = shell_exec_error(($this->gm ? 'gm ' : '') . 'identify -format "%w %h" ' . escapeshellarg($this->src . '[0]'));
if (preg_match('/^(\d+) (\d+)$/', $size, $m)) {
$this->width = $m[1];
$this->height = $m[2];
@@ -251,9 +269,17 @@ class ImageConvert extends ImageBase {
if (!$this->temp) {
if ($config['strip_exif']) {
- shell_exec('convert ' . escapeshellarg($this->src) . ' -auto-orient -strip ' . escapeshellarg($src));
+ if($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
+ escapeshellarg($this->src) . ' -auto-orient -strip ' . escapeshellarg($src))) {
+ $this->destroy();
+ error('Failed to resize image!', null, $error);
+ }
} else {
- shell_exec('convert ' . escapeshellarg($this->src) . ' -auto-orient ' . escapeshellarg($src));
+ if($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
+ escapeshellarg($this->src) . ' -auto-orient ' . escapeshellarg($src))) {
+ $this->destroy();
+ error('Failed to resize image!', null, $error);
+ }
}
} else {
rename($this->temp, $src);
@@ -289,13 +315,25 @@ class ImageConvert extends ImageBase {
escapeshellarg($this->temp) . '2>&1 &&echo $?') !== '0') || !file_exists($this->temp))
error('Failed to resize image!', null, $error);
} else {
- if (trim($error = shell_exec('convert ' . sprintf($config['convert_args'], '', $this->width, $this->height) . ' ' .
- escapeshellarg($this->src) . ' ' . escapeshellarg($this->temp) . ' 2>&1 &&echo $?')) !== '0' || !file_exists($this->temp))
+ if ($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
+ sprintf($config['convert_args'],
+ $this->width,
+ $this->height,
+ escapeshellarg($this->src),
+ $this->width,
+ $this->height,
+ escapeshellarg($this->temp))) || !file_exists($this->temp))
error('Failed to resize image!', null, $error);
}
} else {
- if (trim($error = shell_exec('convert ' . sprintf($config['convert_args'], '-flatten', $this->width, $this->height) . ' ' .
- escapeshellarg($this->src . '[0]') . " " . escapeshellarg($this->temp) . ' 2>&1 &&echo $?')) !== '0' || !file_exists($this->temp))
+ if ($error = shell_exec_error(($this->gm ? 'gm ' : '') . 'convert ' .
+ sprintf($config['convert_args'],
+ $this->width,
+ $this->height,
+ escapeshellarg($this->src . '[0]'),
+ $this->width,
+ $this->height,
+ escapeshellarg($this->temp))) || !file_exists($this->temp))
error('Failed to resize image!', null, $error);
}
}
diff --git a/post.php b/post.php
index b35f33e2..ac355e58 100644
--- a/post.php
+++ b/post.php
@@ -449,22 +449,24 @@ if (isset($_POST['delete'])) {
}
- if ($post['extension'] == 'jpg' || $post['extension'] == 'jpeg') {
+ if ($config['convert_auto_orient'] && ($post['extension'] == 'jpg' || $post['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'] && ($post['extension'] == 'jpg' || $post['extension'] == 'jpeg')))) {
- if ($config['thumb_method'] == 'convert' || $config['thumb_method'] == 'convert+gifsicle') {
+ if (in_array($config['thumb_method'], array('convert', 'convert+gifsicle', 'gm', 'gm+gifsicle'))) {
$exif = exif_read_data($upload);
+ $gm = in_array($config['thumb_method'], array('gm', 'gm+gifsicle'));
if (isset($exif['Orientation']) && $exif['Orientation'] != 1) {
- shell_exec('convert ' . escapeshellarg($upload) . ' -auto-orient ' . escapeshellarg($upload));
+ if($error = shell_exec_error(($gm ? 'gm ' : '') . 'convert ' .
+ escapeshellarg($upload) . ' -auto-orient ' . escapeshellarg($upload)))
+ error('Could not auto-orient image!', null, $error);
}
}
}
}
// create image object
- $image = new Image($upload, $post['extension']);
-
+ $image = new Image($upload, $post['extension'], $size);
if ($image->size->width > $config['max_width'] || $image->size->height > $config['max_height']) {
$image->delete();
error($config['error']['maxsize']);
@@ -505,8 +507,13 @@ if (isset($_POST['delete'])) {
}
if ($config['redraw_image'] || ($config['strip_exif'] && ($post['extension'] == 'jpg' || $post['extension'] == 'jpeg'))) {
- $image->to($post['file']);
- $dont_copy_file = true;
+ if (!$config['redraw_image'] && $config['strip_with_exiftool']) {
+ if($error = shell_exec_error('exiftool -q -all= ' . escapeshellarg($upload)))
+ error('Could not strip EXIF metadata!', null, $error);
+ } else {
+ $image->to($post['file']);
+ $dont_copy_file = true;
+ }
}
$image->destroy();
} else {
@@ -520,7 +527,7 @@ if (isset($_POST['delete'])) {
}
if (!isset($dont_copy_file) || !$dont_copy_file) {
- if (!@move_uploaded_file($_FILES['file']['tmp_name'], $post['file']))
+ if (!@move_uploaded_file($upload, $post['file']))
error($config['error']['nomove']);
}
}