diff --git a/get_data.lib.php b/get_data.lib.php index 8d631b4..62c8a4f 100644 --- a/get_data.lib.php +++ b/get_data.lib.php @@ -3,6 +3,13 @@ require_once('open_db.lib.php'); require_once(__DIR__ . '/lib/purify.inc.php'); require_once(__DIR__ . '/html.lib.php'); +// The longest story HTML, in bytes. HTML Purifier needs seconds for a few megabytes. +define('MAX_STORY_BYTES', 65536); + +function story_too_long($story) { + return strlen((string)$story) > MAX_STORY_BYTES; +} + function display_stories($id = NULL) { global $db, $is_admin, $editable, $action; if (is_null($id)) @@ -10,17 +17,20 @@ function display_stories($id = NULL) { $search = get_search_args(); $page = ''; $nolink = NULL; + $posted = FALSE; if ($action == 'preview') { global $file_src; $date = 'Awaiting posting'; $result = get_post_data(TRUE); $nolink = TRUE; + $posted = TRUE; } else if ($action == 'submit') { $date = 'Posted '.gmdate("Y-m-d H:i"); if (!$is_admin) { $result = get_post_data(TRUE); $nolink = TRUE; + $posted = TRUE; } else { $result = get_query($id); } @@ -90,6 +100,8 @@ date("Y-m-d H:i", strtotime($entry['date'])) . ''; } else { $page .= ''.$title.''; } + } else if ($posted && story_too_long($entry['story'])) { + $page .= '

The story is too long to show.

'."\n"; } else { $page .= purify_story($entry['story'])."\n"; } diff --git a/publish/post.lib.php b/publish/post.lib.php index 4d9b2c9..90aef93 100644 --- a/publish/post.lib.php +++ b/publish/post.lib.php @@ -206,6 +206,10 @@ function validate_data() { $validate['title'] = "You have not submitted a title."; } + if (story_too_long($story)) { + $validate['story'] = 'The story is too long. Please shorten it.'; + } + if ($remove_img && !$story) { $validate['story'] = "You've tried to remove an image without replacing it with text."; } diff --git a/tests/php/Unit/DisplayStoriesTest.php b/tests/php/Unit/DisplayStoriesTest.php index a7c7f62..bfe0f7d 100644 --- a/tests/php/Unit/DisplayStoriesTest.php +++ b/tests/php/Unit/DisplayStoriesTest.php @@ -111,6 +111,15 @@ class DisplayStoriesTest extends TestCase { $this->assertStringNotContainsString('x()', $page); } + // HTML Purifier needs seconds for a few megabytes, so a posted story over the limit is not shown + public function testPreviewDoesNotShowATooLongStory(): void { + $GLOBALS['action'] = 'preview'; + $this->request(array(), array('title' => 'Long', 'author' => 'Me', 'story' => '

x

' . str_repeat('a', 65536))); + $page = display_stories(); + $this->assertStringContainsString('

The story is too long to show.

', $page); + $this->assertStringNotContainsString('x', $page); + } + public function testPreviewShowsAPendingImage(): void { $GLOBALS['action'] = 'preview'; $GLOBALS['file_src'] = '/display?pending=">