Merge branch 'branch-2.10'

This commit is contained in:
Shish 2024-02-08 00:41:38 +00:00
commit 4974359846
42 changed files with 132 additions and 1259 deletions

View file

@ -21,7 +21,7 @@ class CliApp extends \Symfony\Component\Console\Application
$definition->addOption(new InputOption( $definition->addOption(new InputOption(
'--user', '--user',
'-u', '-u',
InputOption::VALUE_NONE, InputOption::VALUE_REQUIRED,
'Log in as the given user' 'Log in as the given user'
)); ));
@ -36,9 +36,10 @@ class CliApp extends \Symfony\Component\Console\Application
$output ??= new ConsoleOutput(); $output ??= new ConsoleOutput();
if ($input->hasParameterOption(['--user', '-u'])) { if ($input->hasParameterOption(['--user', '-u'])) {
$user = User::by_name($input->getOption('user')); $name = $input->getParameterOption(['--user', '-u']);
$user = User::by_name($name);
if (is_null($user)) { if (is_null($user)) {
die("Unknown user"); die("Unknown user '$name'\n");
} else { } else {
send_event(new UserLoginEvent($user)); send_event(new UserLoginEvent($user));
} }

View file

@ -306,18 +306,14 @@ function get_base_href(): string
if (defined("BASE_HREF") && !empty(BASE_HREF)) { if (defined("BASE_HREF") && !empty(BASE_HREF)) {
return BASE_HREF; return BASE_HREF;
} }
$possible_vars = ['SCRIPT_NAME', 'PHP_SELF', 'PATH_INFO', 'ORIG_PATH_INFO']; if(str_ends_with($_SERVER['PHP_SELF'], 'index.php')) {
$ok_var = null; $self = $_SERVER['PHP_SELF'];
foreach ($possible_vars as $var) {
if (isset($_SERVER[$var]) && substr($_SERVER[$var], -4) === '.php') {
$ok_var = $_SERVER[$var];
break;
}
} }
assert(!empty($ok_var)); elseif(isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['DOCUMENT_ROOT'])) {
$dir = dirname($ok_var); $self = substr($_SERVER['SCRIPT_FILENAME'], strlen(rtrim($_SERVER['DOCUMENT_ROOT'], "/")));
}
$dir = dirname($self);
$dir = str_replace("\\", "/", $dir); $dir = str_replace("\\", "/", $dir);
$dir = str_replace("//", "/", $dir);
$dir = rtrim($dir, "/"); $dir = rtrim($dir, "/");
return $dir; return $dir;
} }

View file

@ -254,4 +254,42 @@ class PolyfillsTest extends TestCase
deltree($dir); deltree($dir);
$this->assertFalse(file_exists($dir)); $this->assertFalse(file_exists($dir));
} }
private function _tbh(array $vars, string $result): void
{
// update $_SERVER with $vars, call get_base_href() and check result, then reset $_SERVER to original value
$old_server = $_SERVER;
$_SERVER = array_merge($_SERVER, $vars);
$this->assertEquals($result, get_base_href());
$_SERVER = $old_server;
}
public function test_get_base_href(): void
{
// PHP_SELF should point to "the currently executing script
// relative to the document root"
$this->_tbh(["PHP_SELF" => "/index.php"], "");
$this->_tbh(["PHP_SELF" => "/mydir/index.php"], "/mydir");
// SCRIPT_FILENAME should point to "the absolute pathname of
// the currently executing script" and DOCUMENT_ROOT should
// point to "the document root directory under which the
// current script is executing"
$this->_tbh([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/mydir/index.php",
"DOCUMENT_ROOT" => "/var/www/html",
], "/mydir");
$this->_tbh([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/mydir/index.php",
"DOCUMENT_ROOT" => "/var/www/html/",
], "/mydir");
$this->_tbh([
"PHP_SELF" => "<invalid>",
"SCRIPT_FILENAME" => "/var/www/html/index.php",
"DOCUMENT_ROOT" => "/var/www/html",
], "");
}
} }

View file

@ -162,4 +162,27 @@ class UtilTest extends TestCase
path_to_tags("/category:/tag/baz.jpg") path_to_tags("/category:/tag/baz.jpg")
); );
} }
public function test_get_query(): void
{
// niceurls
$_SERVER["REQUEST_URI"] = "/test/tasty/cake";
$this->assertEquals("/tasty/cake", _get_query());
// no niceurls
$_SERVER["REQUEST_URI"] = "/test/index.php?q=/tasty/cake";
$this->assertEquals("/tasty/cake", _get_query());
// leave url encoding alone
$_SERVER["REQUEST_URI"] = "/test/index.php?q=/tasty/cake%20pie";
$this->assertEquals("/tasty/cake%20pie", _get_query());
// if just viewing index.php
$_SERVER["REQUEST_URI"] = "/test/index.php";
$this->assertEquals("/", _get_query());
// niceurl root
$_SERVER["REQUEST_URI"] = "/test/";
$this->assertEquals("/", _get_query());
}
} }

View file

@ -715,19 +715,33 @@ function _get_user(): User
function _get_query(): string function _get_query(): string
{ {
// if query is explicitly set, use it // if q is set in POST, use that
$q = @$_POST["q"] ?: @$_GET["q"]; if(isset($_POST["q"])) {
if(!empty($q)) { return $_POST["q"];
return $q;
} }
// if q is set in GET, use that
// (we need to manually parse the query string because PHP's $_GET
// does an extra round of URL decoding, which we don't want)
$parts = parse_url($_SERVER['REQUEST_URI']);
$qs = [];
foreach(explode('&', $parts['query'] ?? "") as $z) {
$qps = explode('=', $z, 2);
if(count($qps) == 2) {
$qs[$qps[0]] = $qps[1];
}
}
if(isset($qs["q"])) {
return $qs["q"];
}
// if we're just looking at index.php, use the default query // if we're just looking at index.php, use the default query
elseif (str_contains($_SERVER['REQUEST_URI'], "index.php")) { if(str_ends_with($parts["path"], "index.php")) {
return "/"; return "/";
} }
// otherwise, use the request URI
else { // otherwise, use the request URI minus the base path
return explode("?", $_SERVER['REQUEST_URI'])[0]; return substr($parts["path"], strlen(get_base_href()));
}
} }

View file

@ -117,7 +117,7 @@ class ExtManager extends Extension
} }
/** /**
* @param array<string, bool> $settings * @param array<string, mixed> $settings
*/ */
private function set_things(array $settings): void private function set_things(array $settings): void
{ {
@ -125,7 +125,10 @@ class ExtManager extends Extension
$extras = []; $extras = [];
foreach (ExtensionInfo::get_all_keys() as $key) { foreach (ExtensionInfo::get_all_keys() as $key) {
if (!in_array($key, $core) && isset($settings["ext_$key"])) { if (in_array($key, $core)) {
continue; // core extensions are always enabled
}
if (isset($settings["ext_$key"]) && $settings["ext_$key"] === "on") {
$extras[] = $key; $extras[] = $key;
} }
} }

View file

@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
class Rule34Info extends ExtensionInfo
{
public const KEY = "rule34";
public string $key = self::KEY;
public string $name = "Rule34 Customisations";
public string $url = self::SHIMMIE_URL;
public array $authors = self::SHISH_AUTHOR;
public string $license = self::LICENSE_GPLV2;
public string $description = "Extra site-specific bits";
public ?string $documentation =
"Probably not much use to other sites, but it gives a few examples of how a shimmie-based site can be integrated with other systems";
public array $db_support = [DatabaseDriverID::PGSQL]; # Only PG has the NOTIFY pubsub system
public ExtensionVisibility $visibility = ExtensionVisibility::HIDDEN;
}

View file

@ -1,123 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
use Symfony\Component\Console\Output\OutputInterface;
if (
// kill these glitched requests immediately
!empty($_SERVER["REQUEST_URI"])
&& str_contains(@$_SERVER["REQUEST_URI"], "/http")
&& str_contains(@$_SERVER["REQUEST_URI"], "paheal.net")
) {
die("No");
}
class Rule34 extends Extension
{
public function onImageDeletion(ImageDeletionEvent $event): void
{
global $database;
$database->notify("shm_image_bans", $event->image->hash);
}
public function onImageInfoSet(ImageInfoSetEvent $event): void
{
global $cache;
$cache->delete("thumb-block:{$event->image->id}");
}
public function onAdminBuilding(AdminBuildingEvent $event): void
{
global $page;
$html = make_form(make_link("admin/cache_purge"), "POST");
$html .= "<textarea type='text' name='hash' placeholder='Enter image URL or hash' cols='80' rows='5'></textarea>";
$html .= "<br><input type='submit' value='Purge from caches'>";
$html .= "</form>\n";
$page->add_block(new Block("Cache Purger", $html));
}
public function onCliGen(CliGenEvent $event): void
{
$event->app->register('wipe-thumb-cache')
->addArgument('tags', InputArgument::REQUIRED)
->setDescription('Delete cached thumbnails for images matching the given tags')
->setCode(function (InputInterface $input, OutputInterface $output): int {
global $cache;
$tags = Tag::explode($input->getArgument('tags'));
foreach (Search::find_images_iterable(0, null, $tags) as $image) {
$output->writeln((string)$image->id);
$cache->delete("thumb-block:{$image->id}");
}
return Command::SUCCESS;
});
}
public function onSourceSet(SourceSetEvent $event): void
{
// Maybe check for 404?
if (empty($event->source)) {
return;
}
if (!preg_match("/^(https?:\/\/)?[a-zA-Z0-9\.\-]+(\/.*)?$/", $event->source)) {
throw new SCoreException("Invalid source URL");
}
}
public function onRobotsBuilding(RobotsBuildingEvent $event): void
{
// robots should only check the canonical site, not mirrors
if ($_SERVER['HTTP_HOST'] != "rule34.paheal.net") {
$event->add_disallow("");
}
}
public function onPageRequest(PageRequestEvent $event): void
{
global $database, $page, $user;
# Database might not be connected at this point...
#$database->set_timeout(null); // deleting users can take a while
$page->add_html_header("<meta name='theme-color' content='#7EB977'>");
$page->add_html_header("<meta name='juicyads-site-verification' content='20d309e193510e130c3f8a632f281335'>");
if ($event->page_matches("tnc_agreed")) {
setcookie("ui-tnc-agreed", "true", 0, "/");
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or("/"));
}
if ($event->page_matches("admin/cache_purge")) {
if (!$user->can(Permissions::MANAGE_ADMINTOOLS)) {
$this->theme->display_permission_denied();
} else {
if ($user->check_auth_token()) {
$all = $_POST["hash"];
$matches = [];
if (preg_match_all("/([a-fA-F0-9]{32})/", $all, $matches)) {
$matches = $matches[0];
foreach ($matches as $hash) {
$page->flash("Cleaning {$hash}");
if (strlen($hash) != 32) {
continue;
}
log_info("admin", "Cleaning {$hash}");
@unlink(warehouse_path(Image::IMAGE_DIR, $hash));
@unlink(warehouse_path(Image::THUMBNAIL_DIR, $hash));
$database->notify("shm_image_bans", $hash);
}
}
}
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin"));
}
}
}
}

View file

@ -1,39 +0,0 @@
let tnc_div = document.createElement('div');
tnc_div.innerHTML = `
<div class='tnc_bg'></div>
<div class='tnc'>
<p>Cookies may be used. Please read our <a href='https://rule34.paheal.net/wiki/Privacy%20policy'>privacy policy</a> for more information.
<p>By accepting to enter you agree to our <a href='https://rule34.paheal.net/wiki/rules'>rules</a> and <a href='https://rule34.paheal.net/wiki/Terms%20of%20use'>terms of service</a>.
<p><a onclick='tnc_agree();'>Agree</a> / <a href='https://google.com'>Disagree</a>
</div>
`;
document.addEventListener('DOMContentLoaded', () => {
if(shm_cookie_get("ui-tnc-agreed") !== "true" && window.location.href.indexOf("/wiki/") == -1) {
document.body.classList.add('censored');
document.body.appendChild(tnc_div);
}
});
function tnc_agree() {
shm_cookie_set("ui-tnc-agreed", "true");
document.body.classList.remove('censored');
tnc_div.remove();
}
function image_hash_ban(id) {
var reason = prompt("WHY?", "DNP");
if(reason) {
$.post(
"/image_hash_ban/add",
{
"image_id": id,
"reason": reason,
},
function() {
$("#thumb_" + id).parent().parent().hide();
}
);
}
}

View file

@ -1,35 +0,0 @@
BODY.censored #header,
BODY.censored NAV,
BODY.censored ARTICLE,
BODY.censored FOOTER {
filter: blur(10px);
}
.tnc_bg {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #ACE4A3;
opacity: 0.75;
z-index: 999999999999999999999;
}
.tnc {
position: fixed;
top: 20%;
left: 20%;
right: 20%;
text-align: center;
font-size: 2rem;
background: #ACE4A3;
border: 1px solid #7EB977;
z-index: 9999999999999999999999;
}
@media (max-width: 1024px) {
.tnc {
top: 5%;
left: 5%;
right: 5%;
font-size: 3vw;
}
}

View file

@ -355,30 +355,6 @@ class Setup extends Extension
$themes[$human] = $name; $themes[$human] = $name;
} }
$test_url = str_replace("/index.php", "/nicetest", $_SERVER["SCRIPT_NAME"]);
$nicescript = "<script type='text/javascript'>
checkbox = document.getElementById('nice_urls');
out_span = document.getElementById('nicetest');
checkbox.disabled = true;
out_span.innerHTML = '(testing...)';
document.addEventListener('DOMContentLoaded', () => {
var http_request = new XMLHttpRequest();
http_request.open('GET', '$test_url', false);
http_request.send(null);
if(http_request.status === 200 && http_request.responseText === 'ok') {
checkbox.disabled = false;
out_span.innerHTML = '(tested ok)';
}
else {
checkbox.disabled = true;
out_span.innerHTML = '(test failed)';
}
});
</script>";
$sb = $event->panel->create_new_block("General"); $sb = $event->panel->create_new_block("General");
$sb->position = 0; $sb->position = 0;
$sb->add_text_option(SetupConfig::TITLE, "Site title: "); $sb->add_text_option(SetupConfig::TITLE, "Site title: ");
@ -388,7 +364,7 @@ class Setup extends Extension
$sb->add_choice_option(SetupConfig::THEME, $themes, "<br>Theme: "); $sb->add_choice_option(SetupConfig::THEME, $themes, "<br>Theme: ");
//$sb->add_multichoice_option("testarray", array("a" => "b", "c" => "d"), "<br>Test Array: "); //$sb->add_multichoice_option("testarray", array("a" => "b", "c" => "d"), "<br>Test Array: ");
$sb->add_bool_option("nice_urls", "<br>Nice URLs: "); $sb->add_bool_option("nice_urls", "<br>Nice URLs: ");
$sb->add_label("<span title='$test_url' id='nicetest'>(Javascript inactive, can't test!)</span>$nicescript"); $sb->add_label("<span id='nicetest'>(Javascript inactive, can't test!)</span>");
$sb = $event->panel->create_new_block("Remote API Integration"); $sb = $event->panel->create_new_block("Remote API Integration");
$sb->add_label("<a href='https://akismet.com/'>Akismet</a>"); $sb->add_label("<a href='https://akismet.com/'>Akismet</a>");

29
ext/setup/script.js Normal file
View file

@ -0,0 +1,29 @@
document.addEventListener('DOMContentLoaded', () => {
const checkbox = document.getElementById('nice_urls');
const out_span = document.getElementById('nicetest');
if(checkbox !== null && out_span !== null) {
checkbox.disabled = true;
out_span.innerHTML = '(testing...)';
fetch(document.body.getAttribute('data-base-href') + "/nicetest").then(response => {
if(!response.ok) {
checkbox.disabled = true;
out_span.innerHTML = '(http error)';
} else {
response.text().then(text => {
if(text === 'ok') {
checkbox.disabled = false;
out_span.innerHTML = '(test passed)';
} else {
checkbox.disabled = true;
out_span.innerHTML = '(test failed)';
}
});
}
}).catch(() => {
checkbox.disabled = true;
out_span.innerHTML = '(request failed)';
});
}
});

View file

@ -19,7 +19,10 @@ require_once "core/sys_config.php";
require_once "core/polyfills.php"; require_once "core/polyfills.php";
require_once "core/util.php"; require_once "core/util.php";
$_SERVER['SCRIPT_FILENAME'] = '/var/www/html/test/index.php';
$_SERVER['DOCUMENT_ROOT'] = '/var/www/html';
$_SERVER['QUERY_STRING'] = '/'; $_SERVER['QUERY_STRING'] = '/';
if (file_exists("data/test-trace.json")) { if (file_exists("data/test-trace.json")) {
unlink("data/test-trace.json"); unlink("data/test-trace.json");
} }

View file

@ -20,7 +20,6 @@ define("VERSION", 'unit-tests');
define("TRACE_FILE", null); define("TRACE_FILE", null);
define("TRACE_THRESHOLD", 0.0); define("TRACE_THRESHOLD", 0.0);
define("TIMEZONE", 'UTC'); define("TIMEZONE", 'UTC');
define("BASE_HREF", "/test");
define("CLI_LOG_LEVEL", 50); define("CLI_LOG_LEVEL", 50);
define("STATSD_HOST", null); define("STATSD_HOST", null);
define("TRUSTED_PROXIES", []); define("TRUSTED_PROXIES", []);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 B

View file

@ -1,100 +0,0 @@
<table class="headbox">
<tr>
<td colspan="4" id="big-logo">
<a class="vis-desktop" href="//rule34.paheal.net/post/list"><img alt="logo" src="//rule34.paheal.net/themes/rule34v2/rule34_logo_top.png" style="height: 104px;"/></a>
</td>
</tr>
<tr>
<form action='/post/list' method='GET' id="barbot">
<td id="nav-toggle">
<a style="font-size: 2rem;" onclick="toggleNav();">&nbsp;Sidebar&nbsp;</a>
</td>
<td id="mini-logo">
<a class="vis-mobile" href="//rule34.paheal.net/post/list"><img alt="logo" src="//rule34.paheal.net/themes/rule34v2/rule34_logo_top.png" style="height: 34px;"/></a>
</td>
<td>
<input name='search' size="45" type='text' placeholder='Search' autocomplete='off' class='autocomplete_tags' value="$QUERY"/>
</td>
<td width="100">
<input type='submit' value='Find' id="submit" style="border: 1px solid #888; height: 22px; border-radius: 2px; background: #EEE;"/>
</td>
</form>
</tr>
<tr>
<td colspan="4">
<div id="menuh-container">
<div id="menuh">
<ul>
<li><a href="//rule34.paheal.net/post/list" class="top_parent">Main &#9660;</a>
<ul>
<li><a href="//rule34.paheal.net/post/list" class="sub_option">Home page</a></li>
<li><a href="//rule34.paheal.net/comment/list" class="sub_option">Comments</a></li>
<li><a href="//rule34.paheal.net/tags" class="sub_option">Tags</a></li>
<li><a href="//rule34.paheal.net/upload" class="sub_option">Upload</a></li>
</ul>
</li>
</ul>
<!--<ul class="header-sites">
<li><a href="#" class="top_parent">Sites</a>
<ul>
<li><a href="//rule34.paheal.net/" class="sub_option">Rule #34</a></li>
<li><a href="http://rule63.paheal.net/" class="sub_option">Rule #63</a></li>
<li><a href="http://cosplay.paheal.net/" class="sub_option">Cosplay</a></li>
<li><a href="//rule34c.paheal.net/" class="sub_option">Rule #34c</a></li>
</ul>
</li>
</ul>-->
<ul>
<li><a href="#" class="top_parent">Community &#9660;</a>
<ul>
<!--<li><a href="http://forum.paheal.net" class="sub_option">Forum</a></li>-->
<li><a href="//rule34.paheal.net/wiki/friends" class="parent">Friends of paheal</a>
<li><a href="//rule34.paheal.net/wiki/DNP" class="parent">DNP List</a>
<li><a href="#" class="parent">Chat</a>
<ul>
<li><a href="irc://irc.rizon.net/rule34" class="sub_option">irc.rizon.net/rule34</a></li>
<li><a href="http://widget.mibbit.com/?server=irc.rizon.net&nick=Anon%3F%3F%3F&channel=%23rule34" target="new" class="sub_option">Web Chat</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><a href="//rule34.paheal.net/post/list" class="top_parent">Help &#9660;</a>
<ul>
<li><a href="mailto:dmca@paheal.net" class="sub_option">DMCA</a></li>
<li><a href="//rule34.paheal.net/wiki/rules" class="sub_option">Site rules</a></li>
<li><a href="//rule34.paheal.net/wiki/faq" class="sub_option">F.A.Q.</a></li>
<li><a href="//rule34.paheal.net/wiki/tagging" class="sub_option">Tagging Guide</a></li>
<li><a href="//rule34.paheal.net/wiki/staff" class="sub_option">Staff</a></li>
<li><a href="#" class="parent">Contact</a>
<ul>
<li><a href="mailto:staff@paheal.net" class="sub_option">Staff</a></li>
<li><a href="mailto:webmaster@shishnet.org" class="sub_option">Programmer</a></li>
<li><a href="mailto:dmca@paheal.net" class="sub_option">DMCA</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<!--<ul>
<li><a class="menu top_parent" href="//rule34.paheal.net/wiki/Notes">ANNOUNCEMENTS</a></li>
</ul>-->
<ul>
<li><a href="https://s.zlink3.com/d.php?z=3832265" target="_blank" sub="0002">Adult games! &#127918;</a></li>
</ul>
</div>
</div>
</td>
</tr>
</table>

View file

@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
class CustomIndexTheme extends IndexTheme
{
/** @var string[] */
public static array $_search_query = [];
// override to add the can-del class, so that thumbnail HTML can be cached
// with admin-controls included, and CSS is used to show or hide the controls
protected function build_table(array $images, ?string $query): string
{
global $user;
$candel = $user->can("delete_image") ? "can-del" : "";
$h_query = html_escape($query);
$table = "<div class='shm-image-list $candel' data-query='$h_query'>";
foreach ($images as $image) {
$table .= $this->build_thumb_html($image);
}
$table .= "</div>";
return $table;
}
// Override to add a custom error message
public function display_page(Page $page, $images): void
{
$this->display_page_header($page, $images);
$nav = $this->build_navigation($this->page_number, $this->total_pages, $this->search_terms);
if (!empty($this->search_terms)) {
static::$_search_query = $this->search_terms;
}
$page->add_block(new Block("Navigation", $nav, "left", 0));
if (count($images) > 0) {
$this->display_page_images($page, $images);
} else {
$this->display_error(
404,
"No Posts Found",
"No images were found to match the search criteria. Try looking up a character/series/artist by another name if they go by more than one. Remember to use underscores in place of spaces and not to use commas. If you came to this page by following a link, try using the search box directly instead. See the FAQ for more information."
);
}
}
}

View file

@ -1,121 +0,0 @@
/* Begin CSS Drop Down Menu */
a:link.menu { color:#FF0000; text-decoration: none; }
a:visited.menu { color: #FF0000; text-decoration: none; }
a:hover.menu { color: #FF0000; text-decoration: none; }
a:active.menu { color: #FF0000; text-decoration: none; }
#menuh-container
{
font-size: 1rem;
float: left;
top:0;
left: 5%;
width: 100%;
margin: 0;
}
#menuh
{
font-size: small;
font-family: arial, helvetica, sans-serif;
width:100%;
margin-top: 0;
}
#menuh a.sub_option
{
border: 1px solid #555;
/*background-image:url(topban.jpg);*/
}
#menuh a
{
text-align: center;
background: #ACE4A3;
display:block;
white-space:nowrap;
margin: 0;
padding: 0.2em;
}
#menuh a, #menuh a:visited /* menu at rest */
{
color: #000099;
text-decoration:none;
}
#menuh a:hover /* menu at mouse-over */
{
color: #000000;
}
#menuh a.top_parent, #menuh a.top_parent:hover /* attaches down-arrow to all top-parents */
{
/*background-image: url(navdown_white.gif);*/
background-position: right center;
background-repeat: no-repeat;
}
#menuh a.parent, #menuh a.parent:hover /* attaches side-arrow to all parents */
{
/*background-image: url(nav_white.gif);*/
background-position: right center;
border: 1px solid #555;
background-repeat: no-repeat;
}
#menuh ul
{
list-style:none;
margin:0;
padding:0;
float:left;
width:10em; /* width of all menu boxes */
}
#menuh li
{
position:relative;
min-height: 1px; /* Sophie Dennis contribution for IE7 */
vertical-align: bottom; /* Sophie Dennis contribution for IE7 */
}
#menuh ul ul
{
position:absolute;
z-index:500;
top:auto;
display:none;
padding: 1em;
margin:-1em 0 0 -1em;
}
#menuh ul ul ul
{
top:0;
left:100%;
}
div#menuh li:hover
{
cursor:pointer;
z-index:100;
}
div#menuh li:hover ul ul,
div#menuh li li:hover ul ul,
div#menuh li li li:hover ul ul,
div#menuh li li li li:hover ul ul
{display:none;}
div#menuh li:hover ul,
div#menuh li li:hover ul,
div#menuh li li li:hover ul,
div#menuh li li li li:hover ul
{display:block;}
/* End CSS Drop Down Menu */

View file

@ -1,136 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
class Page extends BasePage
{
public function head_html(): string
{
global $config, $user;
$theme_name = $config->get_string('theme', 'default');
$header_html = $this->get_all_html_headers();
$data_href = get_base_href();
return <<<EOD
<title>{$this->title}</title>
<meta name="description" content="Rule 34, if it exists there is porn of it."/>
<meta name="viewport" content="width=1024">
<meta name="theme-color" content="#7EB977">
<link rel="stylesheet" href="$data_href/themes/$theme_name/menuh.css?_=1" type="text/css">
$header_html
<script defer src="https://unpkg.com/webp-hero@0.0.0-dev.21/dist-cjs/polyfills.js"></script>
<script defer src="https://unpkg.com/webp-hero@0.0.0-dev.21/dist-cjs/webp-hero.bundle.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
webpHero.detectWebpSupport().then(x => {
shm_log("webp", x);
});
var webpMachine = new webpHero.WebpMachine()
webpMachine.polyfillDocument()
});
</script>
<script src="/themes/rule34v2/prebid-ads.js"></script>
EOD;
}
public function body_html(): string
{
global $config, $user;
$left_block_html = "";
$right_block_html = "";
$main_block_html = "";
$head_block_html = "";
$sub_block_html = "";
$main_headings = 0;
foreach ($this->blocks as $block) {
if ($block->section == "main" && !empty($block->header) && $block->header != "Comments") {
$main_headings++;
}
}
foreach ($this->blocks as $block) {
switch ($block->section) {
case "left":
$left_block_html .= $block->get_html(true);
break;
case "right":
$right_block_html .= $block->get_html(true);
break;
case "head":
$head_block_html .= "<td class='headcol'>".$block->get_html(false)."</td>";
break;
case "main":
if ($main_headings == 1) {
$block->header = null;
}
$main_block_html .= $block->get_html(false);
break;
case "subheading":
$sub_block_html .= $block->body; // $block->get_html(true);
break;
default:
print "<p>error: {$block->header} using an unknown section ({$block->section})";
break;
}
}
$query = !empty(CustomIndexTheme::$_search_query) ? html_escape(Tag::implode(CustomIndexTheme::$_search_query)) : "";
// @phpstan-ignore-next-line - yes this is deliberately asserting a constant
assert(!is_null($query)); # used in header.inc, do not remove :P
$flash_html = $this->flash ? "<b id='flash'>".nl2br(html_escape(implode("\n", $this->flash)))."</b>" : "";
$generated = autodate(date('c'));
$footer_html = $this->footer_html();
$header_inc = file_get_contents_ex("themes/rule34v2/header.inc");
assert($header_inc !== false);
$header_inc = str_replace('$QUERY', $query, $header_inc);
return <<<EOD
<table id="header" width="100%">
<tr>
<td>$header_inc</td>
$head_block_html
</tr>
</table>
$sub_block_html
<nav>
$left_block_html
<p>
<a href="//whos.amung.us/show/4vcsbthd"><img src="//whos.amung.us/widget/4vcsbthd.png" style="display:none" alt="web counter" /></a>
</p>
</nav>
<article>
$flash_html
<!-- <h2>Server hardware upgrades will be happening today, expect some downtime while reboots happen~</h2> -->
$main_block_html
</article>
<footer>
<span style="font-size: 12px;">
<a href="http://rule34.paheal.net/wiki/Terms%20of%20use">Terms of use</a>
!!!
<a href="http://rule34.paheal.net/wiki/Privacy%20policy">Privacy policy</a>
!!!
<a href="http://rule34.paheal.net/wiki/2257">18 U.S.C. &sect;2257</a><br />
</span>
<hr />
<br>
Thank you!
Page generated $generated.
$footer_html
</footer>
<!-- BEGIN EroAdvertising ADSPACE CODE -->
<!--<script type="text/javascript" language="javascript" charset="utf-8" src="https://adspaces.ero-advertising.com/adspace/158168.js"></script>-->
<!-- END EroAdvertising ADSPACE CODE -->
EOD;
}
}

View file

@ -1 +0,0 @@
var canRunAds = true;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View file

@ -1,48 +0,0 @@
// Disable things that get in the way of smooth admin'ing
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll("input[type='date']").forEach(e => e.setAttribute('type', 'text'));
});
// Navbar controls
var navHidden = false;
function toggleNav() {
if(navHidden) {
document.body.classList.remove('navHidden');
shm_cookie_set("ui-shownav", "true");
}
else {
document.body.classList.add('navHidden');
shm_cookie_set("ui-shownav", "false");
}
navHidden = !navHidden;
}
document.addEventListener('DOMContentLoaded', () => {
if(shm_cookie_get("ui-shownav") === "false") {
toggleNav();
}
});
// Desktop mode toggle
var forceDesktop = false;
function toggleDesktop() {
if(forceDesktop) {
let viewport = document.querySelector("meta[name=viewport]");
viewport.setAttribute('content', 'width=512');
shm_cookie_set("ui-desktop", "false");
}
else {
let viewport = document.querySelector("meta[name=viewport]");
viewport.setAttribute('content', 'width=1024, initial-scale=0.4');
shm_cookie_set("ui-desktop", "true");
navHidden = true;
toggleNav();
}
forceDesktop = !forceDesktop;
}
document.addEventListener('DOMContentLoaded', () => {
if(shm_cookie_get("ui-desktop") === "true") {
toggleDesktop();
}
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -1,379 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* things common to all pages *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
:root {
font-family: "Arial", sans-serif;
font-size: 14px;
}
BODY {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPBAMAAADJ+Ih5AAAAFVBMVEV8und+uXeo5aKo5qOq5aOr46Ks5KN5+6UZAAAAN0lEQVQImWNIc2FLcUhzYWBIczRLEU5zNGBwEQlxdHURCWBwdEkRcXN0SWBgVkswSgMSDDRTDADa2B2AhUf94AAAAABJRU5ErkJggg==');
margin: 0;
}
#header {
border-bottom: 1px solid #7EB977;
margin-top: 0;
margin-bottom: 16px;
padding: 8px;
background: #ACE4A3;
text-align: center;
}
H1 {
font-size: 5rem;
margin: 0;
padding: 0;
}
H1 A {
color: black;
}
H3 {
text-align: center;
margin: 0;
}
THEAD {
font-weight: bold;
}
TD {
vertical-align: top;
text-align: center;
}
#flash {
background: #FF7;
display: block;
padding: 8px;
margin: 8px;
border: 1px solid #882;
}
TABLE.zebra {background: #ACE4A3; border-collapse: collapse; border: 1px solid #7EB977;}
TABLE.zebra TD {font-size: 0.8rem;margin: 0; border-top: 1px solid #7EB977; padding: 2px;}
TABLE.zebra TR:nth-child(odd) {background: #9CD493;}
TABLE.zebra TR:nth-child(even) {background: #ACE4A3;}
FOOTER {
clear: both;
padding: 8px;
font-size: 0.7rem;
text-align: center;
border-top: 1px solid #7EB977;
background: #ACE4A3;
}
A {color: #000099; text-decoration: none; font-weight: bold;}
A:hover {color: #000099; text-decoration: underline;}
A:visited {color: #000099; text-decoration: none}
A:active {color: #000099; text-decoration: underline;}
UL {
text-align: left;
}
.ad1{
display:flex;
justify-content:center;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* the navigation bar, and all its blocks *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NAV {
width: 250px;
float: left;
text-align: center;
margin-left: 16px;
}
NAV .blockbody {
font-size: 0.85rem;
text-align: center;
}
NAV TABLE {
width: 100%;
}
NAV TD {
vertical-align: middle;
}
NAV INPUT {
width: 100%;
padding: 0;
}
NAV SELECT {
width: 100%;
padding: 0;
}
#Friends_of_Pahealleft {
z-index: 0;
position: relative;
}
.comment .info {
background: #ACE4A3;
border: 1px solid #7EB977;
}
.more:after {
content: " >>>";
}
.tag_count:before {
content: "(";
}
.tag_count:after {
content: ")";
}
#imagelist .blockbody,
#paginator .blockbody {
background: none;
border: none;
box-shadow: none;
}
#commentlistimage .blockbody,
#commentlistrecent .blockbody {
background: none;
border: none;
box-shadow: none;
padding: 0;
}
#commentlistimage .blockbody .comment,
#commentlistrecent .blockbody .comment {
margin-left: 0;
margin-right: 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* the main part of each page *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ARTICLE {
margin-left: 276px;
margin-right: 16px;
text-align: center;
height: 1%;
margin-top: 16px;
}
ARTICLE TABLE {
width: 90%;
margin: auto;
}
NAV SECTION:first-child H3 {
margin-top: 0;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* specific page types *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#pagelist {
margin-top: 32px;
}
#tagmap A {
padding: 8px 4px 8px 4px;
}
SECTION>.blockbody, .comment, .setupblock {
background: #ACE4A3;
margin: 8px;
border: 1px solid #7EB977;
padding: 8px;
}
SECTION>H3 {
text-align: center;
background: #9CD493;
margin: 8px;
border: 1px solid #7EB977;
padding: 8px;
}
.shm-image-list {
justify-items: center;
align-items: end;
}
.thumb {
text-align: center;
}
.thumb IMG {
border: 1px solid #7EB977;
background: #ACE4A3;
padding: 4px;
}
.username {
font-weight: bold;
}
#bans TD, .image_info TD {
vertical-align: middle;
}
#bans INPUT {
font-size: 0.85rem;
}
.need-del {
display: none;
}
.can-del .need-del {
display: inline;
}
.unread {
color: red;
}
[data-tags~="ai-generated"]>A>IMG { background: #BC8F8F; }
[data-tags~="animated"]>A>IMG { background: #CC00CC; }
[data-ext="mp4"]>A>IMG,
[data-ext="webm"]>A>IMG { background: #0000FF; }
#menuh-container {
float: none;
width: 650px;
margin: auto;
}
/*
* Image info - show both edit and view modes at the same time,
* except for Tags, Locked, and the Edit button.
*/
.image_info.infomode-view .edit,
.image_info.infomode-view .view {
display: block;
}
.image_info.infomode-view TR[data-row="Tags"] .view,
.image_info.infomode-view TR[data-row="Locked"] .view,
.image_info INPUT[type="button"][value="Edit"] {
display: none;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* responsive overrides *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@media (max-width: 750px) {
.atoz, #paginator {
font-size: 2rem;
}
.header-sites {
display: none;
}
SECTION>.blockbody {
overflow-x: auto;
}
}
/* responsive padding */
@media (max-width: 1024px) {
NAV {margin-left: 0;}
ARTICLE {margin-right: 0; margin-left: 242px;}
}
@media (max-width: 750px) {
NAV {margin-left: 0;}
ARTICLE {margin-right: 0; margin-left: 250px;}
}
/* responsive navbar */
#nav-toggle {display: none;}
@media (max-width: 750px) {
TD#nav-toggle {display: table-cell; width: 40px;}
#nav-toggle A {border: 1px solid black; border-radius: 8px;}
#nav-toggle A:hover {text-decoration: none;}
NAV>SECTION>.blockbody,
NAV>SECTION>.blockbody>.comment {
margin: 0;
}
NAV>SECTION>H3 {
margin: 0;
}
BODY.navHidden #menuh-container {display: none;}
BODY.navHidden NAV {display: none;}
BODY.navHidden ARTICLE {margin-left: 0;}
/*
NAV {
position: fixed;
top: 6.5em;
bottom: 0px;
overflow-y: scroll;
}
*/
}
/* sticky header */
@media (max-width: 750px) {
BODY.navHidden {padding-top: 5.4em}
}
@media (max-width: 750px) {
#header {position: fixed; top: 0; left: 0; z-index: 99999999999;}
.ui-autocomplete {z-index: 999999999999;}
BODY {padding-top: 7em}
}
/* responsive header */
#Uploadleft {display: none;}
#Uploadhead {display: block;}
#UserBlockleft {display: none;}
#UserBlockhead {display: block;}
#Loginleft {display: none;}
#Loginhead {display: block;}
.headcol {width: 250px; font-size: 0.85rem;}
.headbox {width: 80%; margin: auto;}
.headbox INPUT {width: 100%;}
#big-logo {display: table-cell;}
#mini-logo {display: none;}
@media (max-width: 1024px) {
#Uploadleft {display: block;}
#Uploadhead {display: none;}
#UserBlockleft {display: block;}
#UserBlockhead {display: none;}
#Loginleft {display: block;}
#Loginhead {display: none;}
.headcol {display: none;}
.headbox {width: 100%; margin: auto;}
#big-logo {display: none;}
#mini-logo {display: table-cell; width: 100px;}
/* hide nav-search when header-search is sticky */
ARTICLE {margin-top: 0;}
#Navigationleft .blockbody {font-size: 1.5rem;}
#Navigationleft .blockbody P,
#Navigationleft .blockbody FORM
{display: none;}
}
/* responsive comments */
.comment_list_table {width: 100%;}
/* responsive misc */
@media (max-width: 750px) {
#shm-main-image { max-width: 95%; }
}
#ed91727bc9c7a73fdcec6db562e63151main {
overflow: scroll;
}
/* front page */
div#front-page h1 {font-size: 4rem; margin-top: 2em; margin-bottom: 0; text-align: center; border: none; background: none; box-shadow: none; -webkit-box-shadow: none; -moz-box-shadow: none;}
div#front-page {text-align:center;}
.space {margin-bottom: 1em;}
div#front-page div#links a {margin: 0 0.5em;}
div#front-page li {list-style-type: none; margin: 0;}
@media (max-width: 800px) {
div#front-page h1 {font-size: 3rem; margin-top: 0.5em; margin-bottom: 0.5em;}
#counter {display: none;}
}

View file

@ -1,53 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
use MicroHTML\HTMLElement;
use function MicroHTML\{A,BR,DIV,IMG,SPAN,rawHTML};
class Themelet extends BaseThemelet
{
public function build_thumb_html(Image $image): HTMLElement
{
global $cache, $config;
$cached = $cache->get("thumb-block:{$image->id}");
if (!is_null($cached)) {
return rawHTML($cached);
}
$id = $image->id;
$view_link = make_link('post/view/'.$id);
$image_link = $image->get_image_link();
$thumb_link = $image->get_thumb_link();
$tip = $image->get_tooltip();
$tags = strtolower($image->get_tag_list());
$ext = strtolower($image->get_ext());
// If file is flash or svg then sets thumbnail to max size.
if ($image->get_mime() === MimeType::FLASH || $image->get_mime() === MimeType::SVG) {
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
} else {
$tsize = get_thumbnail_size($image->width, $image->height);
}
$html = DIV(
['class' => 'shm-thumb thumb', 'data-ext' => $ext, 'data-tags' => $tags, 'data-post-id' => $id],
A(
['class' => 'shm-thumb-link', 'href' => $view_link],
IMG(['id' => "thumb_$id", 'title' => $tip, 'alt' => $tip, 'height' => $tsize[1], 'width' => $tsize[0], 'src' => $thumb_link, 'loading' => 'lazy'])
),
BR(),
A(['href' => $image_link], 'File Only'),
SPAN(['class' => 'need-del'], ' - ', A(['href' => '#', 'onclick' => "image_hash_ban($id); return false;"], 'Ban'))
);
// cache for ages; will be cleared in ext/index:onImageInfoSet
$cache->set("thumb-block:{$image->id}", (string)$html, rand(43200, 86400));
return $html;
}
}

View file

@ -1,44 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
use MicroHTML\HTMLElement;
use function MicroHTML\TABLE;
use function MicroHTML\TR;
use function MicroHTML\TD;
use function MicroHTML\SMALL;
use function MicroHTML\rawHTML;
use function MicroHTML\INPUT;
use function MicroHTML\emptyHTML;
use function MicroHTML\NOSCRIPT;
use function MicroHTML\DIV;
use function MicroHTML\BR;
use function MicroHTML\A;
use function MicroHTML\P;
class CustomUploadTheme extends UploadTheme
{
// override to put upload block in head and left
// (with css media queries deciding which one is visible)
public function display_block(Page $page): void
{
$page->add_block(new Block("Upload", $this->build_upload_block(), "head", 20));
$page->add_block(new Block("Upload", $this->build_upload_block(), "left", 20));
}
// override to put the warning in the header
public function display_full(Page $page): void
{
$page->add_block(new Block("Upload", "Disk nearly full, uploads disabled", "head", 20));
}
// override to remove small uploader and just show a link to
// the big page
protected function build_upload_block(): HTMLElement
{
return A(["href" => make_link("upload"), "style" => 'font-size: 1.7rem; display: block;'], "Upload");
}
}

View file

@ -1,59 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
use function MicroHTML\emptyHTML;
use function MicroHTML\rawHTML;
use function MicroHTML\TABLE;
use function MicroHTML\TBODY;
use function MicroHTML\TFOOT;
use function MicroHTML\TR;
use function MicroHTML\TH;
use function MicroHTML\TD;
use function MicroHTML\LABEL;
use function MicroHTML\INPUT;
use function MicroHTML\SMALL;
use function MicroHTML\A;
use function MicroHTML\BR;
use function MicroHTML\P;
use function MicroHTML\SELECT;
use function MicroHTML\OPTION;
class CustomUserPageTheme extends UserPageTheme
{
// Override to display user block in the head and in the left column
// (with css media queries deciding which one is visible), and also
// to switch between new-line and inline display depending on the
// number of links.
/**
* @param array<array{link: string, name: string}> $parts
*/
public function display_user_block(Page $page, User $user, array $parts): void
{
$h_name = html_escape($user->name);
$lines = [];
foreach ($parts as $part) {
if ($part["name"] == "User Options") {
continue;
}
$lines[] = "<a href='{$part["link"]}'>{$part["name"]}</a>";
}
if (count($lines) < 6) {
$html = implode("\n<br>", $lines);
} else {
$html = implode(" | \n", $lines);
}
$page->add_block(new Block("Logged in as $h_name", $html, "head", 90, "UserBlockhead"));
$page->add_block(new Block("Logged in as $h_name", $html, "left", 15, "UserBlockleft"));
}
// Override to display login block in the head and in the left column
// (with css media queries deciding which one is visible)
public function display_login_block(Page $page): void
{
$page->add_block(new Block("Login", $this->create_login_block(), "head", 90));
$page->add_block(new Block("Login", $this->create_login_block(), "left", 15));
}
}