From 409b91e8611a6cffb2f3cbc88991512916952ec4 Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Thu, 8 Oct 2020 11:02:25 -0700 Subject: [PATCH] Allow files to be uploaded via URL Resolves #82. --- imgboard.php | 186 ++++++++++++------------------------------- inc/defines.php | 3 + inc/functions.php | 122 +++++++++++++++++++++++++++- inc/html.php | 32 ++++---- settings.default.php | 1 + 5 files changed, 193 insertions(+), 151 deletions(-) diff --git a/imgboard.php b/imgboard.php index 3cc3fbc..8436545 100644 --- a/imgboard.php +++ b/imgboard.php @@ -25,6 +25,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + use Gettext\Translator; use Gettext\Translations; @@ -62,7 +63,7 @@ if (!file_exists('settings.php')) { } require 'settings.php'; -if (TINYIB_LOCALE == '') { +if (!defined('TINYIB_LOCALE') || TINYIB_LOCALE == '') { function __($string) { return $string; } @@ -175,154 +176,67 @@ if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) list($service, $embed) = getEmbed(trim($_POST['embed'])); if (empty($embed) || !isset($embed['html']) || !isset($embed['title']) || !isset($embed['thumbnail_url'])) { - fancyDie(sprintf(__('Invalid embed URL. Only %s URLs are supported.'), implode('/', array_keys($tinyib_embeds)))); - } - - $post['file_hex'] = $service; - $temp_file = time() . substr(microtime(), 2, 3); - $file_location = "thumb/" . $temp_file; - file_put_contents($file_location, url_get_contents($embed['thumbnail_url'])); - - $file_info = getimagesize($file_location); - $file_mime = mime_content_type($file_location); - $post['image_width'] = $file_info[0]; - $post['image_height'] = $file_info[1]; - - if ($file_mime == "image/jpeg") { - $post['thumb'] = $temp_file . '.jpg'; - } else if ($file_mime == "image/gif") { - $post['thumb'] = $temp_file . '.gif'; - } else if ($file_mime == "image/png") { - $post['thumb'] = $temp_file . '.png'; - } else { - fancyDie(__('Error while processing audio/video.')); - } - $thumb_location = "thumb/" . $post['thumb']; - - list($thumb_maxwidth, $thumb_maxheight) = thumbnailDimensions($post); - - if (!createThumbnail($file_location, $thumb_location, $thumb_maxwidth, $thumb_maxheight)) { - fancyDie(__('Could not create thumbnail.')); - } - - addVideoOverlay($thumb_location); - - $thumb_info = getimagesize($thumb_location); - $post['thumb_width'] = $thumb_info[0]; - $post['thumb_height'] = $thumb_info[1]; - - $post['file_original'] = cleanString($embed['title']); - $post['file'] = str_ireplace(array('src="https://', 'src="http://'), 'src="//', $embed['html']); - } else if (isset($_FILES['file']) && ($rawpost || !in_array('file', $hide_fields))) { - if ($_FILES['file']['name'] != "") { - validateFileUpload(); - - if (!is_file($_FILES['file']['tmp_name']) || !is_readable($_FILES['file']['tmp_name'])) { - fancyDie(__('File transfer failure. Please retry the submission.')); + if (!TINYIB_UPLOADVIAURL) { + fancyDie(sprintf(__('Invalid embed URL. Only %s URLs are supported.'), implode('/', array_keys($tinyib_embeds)))); } - - if ((TINYIB_MAXKB > 0) && (filesize($_FILES['file']['tmp_name']) > (TINYIB_MAXKB * 1024))) { + $headers = get_headers(trim($_POST['embed']), true); + if (TINYIB_MAXKB > 0 && intval($headers['Content-Length']) > (TINYIB_MAXKB * 1024)) { fancyDie(sprintf(__('That file is larger than %s.'), TINYIB_MAXKBDESC)); } - $post['file_original'] = trim(htmlentities(substr($_FILES['file']['name'], 0, 50), ENT_QUOTES)); - $post['file_hex'] = md5_file($_FILES['file']['tmp_name']); - $post['file_size'] = $_FILES['file']['size']; - $post['file_size_formatted'] = convertBytes($post['file_size']); + $data = url_get_contents(trim($_POST['embed'])); + if (strlen($data) == 0) { + fancyDie(__('Failed to download file at specified URL.')); + } - checkDuplicateFile($post['file_hex']); + $filepath = 'src/' . time() . substr(microtime(), 2, 3) . rand(1000, 9999) . '.txt'; + if (!file_put_contents($filepath, $data)) { + @unlink($filepath); + fancyDie(__('Failed to download file at specified URL.')); + } - $file_mime_split = explode(' ', trim(mime_content_type($_FILES['file']['tmp_name']))); - if (count($file_mime_split) > 0) { - $file_mime = strtolower(array_pop($file_mime_split)); + $post = attachFile($post, $filepath, basename(parse_url(trim($_POST['embed']), PHP_URL_PATH)), false); + } else { + $post['file_hex'] = $service; + $temp_file = time() . substr(microtime(), 2, 3); + $file_location = "thumb/" . $temp_file; + file_put_contents($file_location, url_get_contents($embed['thumbnail_url'])); + + $file_info = getimagesize($file_location); + $file_mime = mime_content_type($file_location); + $post['image_width'] = $file_info[0]; + $post['image_height'] = $file_info[1]; + + if ($file_mime == "image/jpeg") { + $post['thumb'] = $temp_file . '.jpg'; + } else if ($file_mime == "image/gif") { + $post['thumb'] = $temp_file . '.gif'; + } else if ($file_mime == "image/png") { + $post['thumb'] = $temp_file . '.png'; } else { - if (!@getimagesize($_FILES['file']['tmp_name'])) { - fancyDie(__('Failed to read the MIME type and size of the uploaded file. Please retry the submission.')); - } + fancyDie(__('Error while processing audio/video.')); + } + $thumb_location = "thumb/" . $post['thumb']; - $file_info = getimagesize($_FILES['file']['tmp_name']); - $file_mime = mime_content_type($_FILES['file']['tmp_name']); + list($thumb_maxwidth, $thumb_maxheight) = thumbnailDimensions($post); + + if (!createThumbnail($file_location, $thumb_location, $thumb_maxwidth, $thumb_maxheight)) { + fancyDie(__('Could not create thumbnail.')); } - if (empty($file_mime) || !isset($tinyib_uploads[$file_mime])) { - fancyDie(supportedFileTypes()); - } + addVideoOverlay($thumb_location); - $file_name = time() . substr(microtime(), 2, 3); - $post['file'] = $file_name . "." . $tinyib_uploads[$file_mime][0]; + $thumb_info = getimagesize($thumb_location); + $post['thumb_width'] = $thumb_info[0]; + $post['thumb_height'] = $thumb_info[1]; - $file_location = "src/" . $post['file']; - if (!move_uploaded_file($_FILES['file']['tmp_name'], $file_location)) { - fancyDie(__('Could not copy uploaded file.')); - } - - if ($_FILES['file']['size'] != filesize($file_location)) { - @unlink($file_location); - fancyDie(__('File transfer failure. Please go back and try again.')); - } - - if ($file_mime == "audio/webm" || $file_mime == "video/webm" || $file_mime == "audio/mp4" || $file_mime == "video/mp4") { - $post['image_width'] = max(0, intval(shell_exec('mediainfo --Inform="Video;%Width%" ' . $file_location))); - $post['image_height'] = max(0, intval(shell_exec('mediainfo --Inform="Video;%Height%" ' . $file_location))); - - if ($post['image_width'] > 0 && $post['image_height'] > 0) { - list($thumb_maxwidth, $thumb_maxheight) = thumbnailDimensions($post); - $post['thumb'] = $file_name . "s.jpg"; - shell_exec("ffmpegthumbnailer -s " . max($thumb_maxwidth, $thumb_maxheight) . " -i $file_location -o thumb/{$post['thumb']}"); - - $thumb_info = getimagesize("thumb/" . $post['thumb']); - $post['thumb_width'] = $thumb_info[0]; - $post['thumb_height'] = $thumb_info[1]; - - if ($post['thumb_width'] <= 0 || $post['thumb_height'] <= 0) { - @unlink($file_location); - @unlink("thumb/" . $post['thumb']); - fancyDie(__('Sorry, your video appears to be corrupt.')); - } - - addVideoOverlay("thumb/" . $post['thumb']); - } - - $duration = intval(shell_exec('mediainfo --Inform="General;%Duration%" ' . $file_location)); - if ($duration > 0) { - $mins = floor(round($duration / 1000) / 60); - $secs = str_pad(floor(round($duration / 1000) % 60), 2, "0", STR_PAD_LEFT); - - $post['file_original'] = "$mins:$secs" . ($post['file_original'] != '' ? (', ' . $post['file_original']) : ''); - } - } else if (in_array($file_mime, array('image/jpeg', 'image/pjpeg', 'image/png', 'image/gif', 'application/x-shockwave-flash'))) { - $file_info = getimagesize($file_location); - - $post['image_width'] = $file_info[0]; - $post['image_height'] = $file_info[1]; - } - - if (isset($tinyib_uploads[$file_mime][1])) { - $thumbfile_split = explode(".", $tinyib_uploads[$file_mime][1]); - $post['thumb'] = $file_name . "s." . array_pop($thumbfile_split); - if (!copy($tinyib_uploads[$file_mime][1], "thumb/" . $post['thumb'])) { - @unlink($file_location); - fancyDie(__('Could not create thumbnail.')); - } - if ($file_mime == "application/x-shockwave-flash") { - addVideoOverlay("thumb/" . $post['thumb']); - } - } else if (in_array($file_mime, array('image/jpeg', 'image/pjpeg', 'image/png', 'image/gif'))) { - $post['thumb'] = $file_name . "s." . $tinyib_uploads[$file_mime][0]; - list($thumb_maxwidth, $thumb_maxheight) = thumbnailDimensions($post); - - if (!createThumbnail($file_location, "thumb/" . $post['thumb'], $thumb_maxwidth, $thumb_maxheight)) { - @unlink($file_location); - fancyDie(__('Could not create thumbnail.')); - } - } - - if ($post['thumb'] != '') { - $thumb_info = getimagesize("thumb/" . $post['thumb']); - $post['thumb_width'] = $thumb_info[0]; - $post['thumb_height'] = $thumb_info[1]; - } + $post['file_original'] = cleanString($embed['title']); + $post['file'] = str_ireplace(array('src="https://', 'src="http://'), 'src="//', $embed['html']); } + } else if (isset($_FILES['file']) && $_FILES['file']['name'] != "" && ($rawpost || !in_array('file', $hide_fields))) { + validateFileUpload(); + + $post = attachFile($post, $_FILES['file']['tmp_name'], $_FILES['file']['name'], true); } if ($post['file'] == '') { // No file uploaded diff --git a/inc/defines.php b/inc/defines.php index 8b9a9a9..e52d992 100644 --- a/inc/defines.php +++ b/inc/defines.php @@ -28,6 +28,9 @@ if (!defined('TINYIB_MAXHOP')) { if (!defined('TINYIB_THUMBNAIL')) { define('TINYIB_THUMBNAIL', 'gd'); } +if (!defined('TINYIB_UPLOADVIAURL')) { + define('TINYIB_UPLOADVIAURL', false); +} if (!defined('TINYIB_NOFILEOK')) { define('TINYIB_NOFILEOK', false); } diff --git a/inc/functions.php b/inc/functions.php index 6844a23..6fcf76f 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -241,7 +241,7 @@ function writePage($filename, $contents) { } function fixLinksInRes($html) { - $search = array(' href="css/', ' src="js/', ' href="src/', ' href="thumb/', ' href="res/', ' href="imgboard.php', ' href="catalog.html', ' href="favicon.ico', 'src="thumb/', 'src="inc/', 'src="sticky.png', 'src="lock.png', ' action="imgboard.php', ' action="catalog.html'); + $search = array(' href="css/', ' src="js/', ' href="src/', ' href="thumb/', ' href="res/', ' href="imgboard.php', ' href="catalog.html', ' href="favicon.ico', 'src="thumb/', 'src="inc/', 'src="sticky.png', 'src="lock.png', ' action="imgboard.php', ' action="catalog.html'); $replace = array(' href="../css/', ' src="../js/', ' href="../src/', ' href="../thumb/', ' href="../res/', ' href="../imgboard.php', ' href="../catalog.html', ' href="../favicon.ico', 'src="../thumb/', 'src="../inc/', 'src="../sticky.png', 'src="../lock.png', ' action="../imgboard.php', ' action="../catalog.html'); return str_replace($search, $replace, $html); @@ -639,6 +639,126 @@ function getEmbed($url) { return array('', array()); } +function attachFile($post, $filepath, $filename, $uploaded) { + global $tinyib_uploads; + + if (!is_file($filepath) || !is_readable($filepath)) { + @unlink($filepath); + fancyDie(__('File transfer failure. Please retry the submission.')); + } + + $filesize = filesize($filepath); + if (TINYIB_MAXKB > 0 && $filesize > (TINYIB_MAXKB * 1024)) { + @unlink($filepath); + fancyDie(sprintf(__('That file is larger than %s.'), TINYIB_MAXKBDESC)); + } + + $post['file_original'] = trim(htmlentities(substr($filename, 0, 50), ENT_QUOTES)); + $post['file_hex'] = md5_file($filepath); + $post['file_size'] = $filesize; + $post['file_size_formatted'] = convertBytes($post['file_size']); + + checkDuplicateFile($post['file_hex']); + + $file_mime_split = explode(' ', trim(mime_content_type($filepath))); + if (count($file_mime_split) > 0) { + $file_mime = strtolower(array_pop($file_mime_split)); + } else { + if (!@getimagesize($filepath)) { + @unlink($filepath); + fancyDie(__('Failed to read the MIME type and size of the uploaded file. Please retry the submission.')); + } + $file_mime = mime_content_type($filepath); + } + if (empty($file_mime) || !isset($tinyib_uploads[$file_mime])) { + fancyDie(supportedFileTypes()); + } + + $file_name = time() . substr(microtime(), 2, 3); + $post['file'] = $file_name . '.' . $tinyib_uploads[$file_mime][0]; + + $file_location = 'src/' . $post['file']; + if ($uploaded) { + if (!move_uploaded_file($filepath, $file_location)) { + fancyDie(__('Could not copy uploaded file.')); + } + } else { + if (!rename($filepath, $file_location)) { + @unlink($filepath); + fancyDie(__('Could not copy uploaded file.')); + } + } + + if (filesize($file_location) != $filesize) { + @unlink($file_location); + fancyDie(__('File transfer failure. Please go back and try again.')); + } + + if ($file_mime == 'audio/webm' || $file_mime == 'video/webm' || $file_mime == 'audio/mp4' || $file_mime == 'video/mp4') { + $post['image_width'] = max(0, intval(shell_exec('mediainfo --Inform="Video;%Width%" ' . $file_location))); + $post['image_height'] = max(0, intval(shell_exec('mediainfo --Inform="Video;%Height%" ' . $file_location))); + + if ($post['image_width'] > 0 && $post['image_height'] > 0) { + list($thumb_maxwidth, $thumb_maxheight) = thumbnailDimensions($post); + $post['thumb'] = $file_name . 's.jpg'; + shell_exec("ffmpegthumbnailer -s " . max($thumb_maxwidth, $thumb_maxheight) . " -i $file_location -o thumb/{$post['thumb']}"); + + $thumb_info = getimagesize('thumb/' . $post['thumb']); + $post['thumb_width'] = $thumb_info[0]; + $post['thumb_height'] = $thumb_info[1]; + + if ($post['thumb_width'] <= 0 || $post['thumb_height'] <= 0) { + @unlink($file_location); + @unlink('thumb/' . $post['thumb']); + fancyDie(__('Sorry, your video appears to be corrupt.')); + } + + addVideoOverlay('thumb/' . $post['thumb']); + } + + $duration = intval(shell_exec('mediainfo --Inform="General;%Duration%" ' . $file_location)); + if ($duration > 0) { + $mins = floor(round($duration / 1000) / 60); + $secs = str_pad(floor(round($duration / 1000) % 60), 2, '0', STR_PAD_LEFT); + + $post['file_original'] = "$mins:$secs" . ($post['file_original'] != '' ? (', ' . $post['file_original']) : ''); + } + } else if (in_array($file_mime, array('image/jpeg', 'image/pjpeg', 'image/png', 'image/gif', 'application/x-shockwave-flash'))) { + $file_info = getimagesize($file_location); + + $post['image_width'] = $file_info[0]; + $post['image_height'] = $file_info[1]; + } + + if (isset($tinyib_uploads[$file_mime][1])) { + $thumbfile_split = explode('.', $tinyib_uploads[$file_mime][1]); + $post['thumb'] = $file_name . 's.' . array_pop($thumbfile_split); + if (!copy($tinyib_uploads[$file_mime][1], 'thumb/' . $post['thumb'])) { + @unlink($file_location); + fancyDie(__('Could not create thumbnail.')); + } + if ($file_mime == 'application/x-shockwave-flash') { + addVideoOverlay('thumb/' . $post['thumb']); + } + } else if (in_array($file_mime, array('image/jpeg', 'image/pjpeg', 'image/png', 'image/gif'))) { + $post['thumb'] = $file_name . 's.' . $tinyib_uploads[$file_mime][0]; + list($thumb_maxwidth, $thumb_maxheight) = thumbnailDimensions($post); + + if (!createThumbnail($file_location, 'thumb/' . $post['thumb'], $thumb_maxwidth, $thumb_maxheight)) { + @unlink($file_location); + fancyDie(__('Could not create thumbnail.')); + } + } + + if ($post['thumb'] != '') { + $thumb_info = getimagesize('thumb/' . $post['thumb']); + $post['thumb_width'] = $thumb_info[0]; + $post['thumb_height'] = $thumb_info[1]; + } + + return $post; +} + function installedViaGit() { return is_dir('.git'); } diff --git a/inc/html.php b/inc/html.php index aefaad4..f70c78f 100644 --- a/inc/html.php +++ b/inc/html.php @@ -189,9 +189,13 @@ EOF; EOF; } - if (!empty($tinyib_embeds) && ($raw_post || !in_array('embed', $hide_fields))) { + $embeds_enabled = !empty($tinyib_embeds) && ($raw_post || !in_array('embed', $hide_fields)); + if (TINYIB_UPLOADVIAURL || $embeds_enabled) { $txt_embed = __('Embed'); - $txt_embed_help = __('(paste a YouTube URL)'); + $txt_embed_help = ''; + if ($embeds_enabled) { + $txt_embed_help = __('(paste a YouTube URL)'); + } $embed_input_html = << @@ -204,11 +208,11 @@ EOF; EOF; } - if (TINYIB_REQMOD == 'all') { - $reqmod_html = '
  • ' . __('All posts are moderated before being shown.') . '
  • '; - } else if (TINYIB_REQMOD == 'files') { - $reqmod_html = '
  • ' . __('All posts with a file attached are moderated before being shown.') . '
  • '; - } + if (TINYIB_REQMOD == 'all') { + $reqmod_html = '
  • ' . __('All posts are moderated before being shown.') . '
  • '; + } else if (TINYIB_REQMOD == 'files') { + $reqmod_html = '
  • ' . __('All posts with a file attached are moderated before being shown.') . '
  • '; + } $thumbnails_html = ''; if (isset($tinyib_uploads['image/jpeg']) || isset($tinyib_uploads['image/pjpeg']) || isset($tinyib_uploads['image/png']) || isset($tinyib_uploads['image/gif'])) { @@ -222,7 +226,7 @@ EOF; $unique_posts = uniquePosts(); if ($unique_posts > 0) { - $unique_posts_html = '
  • ' . printf(__('Currently %s unique user posts.'), $unique_posts) . '
  • ' . "\n"; + $unique_posts_html = '
  • ' . sprintf(__('Currently %s unique user posts.'), $unique_posts) . '
  • ' . "\n"; } $output = <<] ['; if ($isadmin) { - $output.= '' . __('Bans') . '] ['; + $output .= '' . __('Bans') . '] ['; } - $output.= '' . __('Moderate Post') . '] [' . __('Raw Post') . '] ['; + $output .= '' . __('Moderate Post') . '] [' . __('Raw Post') . '] ['; if ($isadmin) { - $output.= '' . __('Rebuild All') . '] ['; + $output .= '' . __('Rebuild All') . '] ['; } if ($isadmin && installedViaGit()) { $output .= '' . __('Update') . '] ['; } if ($isadmin && TINYIB_DBMIGRATE) { - $output.= '' . __('Migrate Database') . '] ['; + $output .= '' . __('Migrate Database') . '] ['; } - $output.= '' . __('Log Out') . '] · ' . $return; + $output .= '' . __('Log Out') . '] · ' . $return; return $output; } @@ -1026,7 +1030,7 @@ function buildSinglePostJSON($post) { $output = array('id' => $post['id'], 'parent' => $post['parent'], 'timestamp' => $post['timestamp'], 'bumped' => $post['bumped'], 'name' => $name, 'tripcode' => $post['tripcode'], 'subject' => $post['subject'], 'message' => $post['message'], 'file' => $post['file'], 'file_hex' => $post['file_hex'], 'file_original' => $post['file_original'], 'file_size' => $post['file_size'], 'file_size_formated' => $post['file_size_formatted'], 'image_width' => $post['image_width'], 'image_height' => $post['image_height'], 'thumb' => $post['thumb'], 'thumb_width' => $post['thumb_width'], 'thumb_height' => $post['thumb_height']); - if($post['parent'] == TINYIB_NEWTHREAD) { + if ($post['parent'] == TINYIB_NEWTHREAD) { $replies = count(postsInThreadByID($post['id'])) - 1; $images = imagesInThreadByID($post['id']); diff --git a/settings.default.php b/settings.default.php index 0d4d582..ef8f046 100644 --- a/settings.default.php +++ b/settings.default.php @@ -75,6 +75,7 @@ $tinyib_embeds = array('SoundCloud' => 'https://soundcloud.com/oembed?format=jso define('TINYIB_MAXKB', 2048); // Maximum file size in kilobytes [0 to disable] define('TINYIB_MAXKBDESC', '2 MB'); // Human-readable representation of the maximum file size define('TINYIB_THUMBNAIL', 'gd'); // Thumbnail method to use: gd / imagemagick (see README for instructions) +define('TINYIB_UPLOADVIAURL', false); // Allow files to be uploaded via URL define('TINYIB_NOFILEOK', false); // Allow the creation of new threads without uploading a file // Thumbnail size - new thread