PSR-2. I'm not a huge fan, but ugly consistency beats no consistency...

autocomplete
Shish 4 years ago
parent 5ec3e89884
commit 34b05cca7c
  1. 2
      .editorconfig
  2. 1
      .gitignore
  3. 18
      .php_cs.dist
  4. 18
      core/_bootstrap.php
  5. 336
      core/_install.php
  6. 244
      core/basethemelet.php
  7. 147
      core/block.php
  8. 396
      core/cacheengine.php
  9. 93
      core/captcha.php
  10. 490
      core/config.php
  11. 759
      core/database.php
  12. 310
      core/dbengine.php
  13. 136
      core/email.php
  14. 515
      core/event.php
  15. 16
      core/exceptions.php
  16. 301
      core/extension.php
  17. 193
      core/imageboard/event.php
  18. 1774
      core/imageboard/image.php
  19. 128
      core/imageboard/misc.php
  20. 95
      core/imageboard/search.php
  21. 151
      core/imageboard/tag.php
  22. 68
      core/logging.php
  23. 675
      core/page.php
  24. 1071
      core/polyfills.php
  25. 205
      core/send_event.php
  26. 9
      core/sys_config.php
  27. 71
      core/tests/polyfills.test.php
  28. 144
      core/urls.php
  29. 438
      core/user.php
  30. 354
      core/userclass.php
  31. 795
      core/util.php
  32. 470
      ext/admin/main.php
  33. 169
      ext/admin/test.php
  34. 115
      ext/admin/theme.php
  35. 297
      ext/alias_editor/main.php
  36. 179
      ext/alias_editor/test.php
  37. 78
      ext/alias_editor/theme.php
  38. 124
      ext/amazon_s3/main.php
  39. 135
      ext/arrowkey_navigation/main.php
  40. 551
      ext/artists/main.php
  41. 15
      ext/artists/test.php
  42. 691
      ext/artists/theme.php
  43. 97
      ext/autocomplete/main.php
  44. 20
      ext/autocomplete/theme.php
  45. 149
      ext/ban_words/main.php
  46. 55
      ext/ban_words/test.php
  47. 289
      ext/bbcode/main.php
  48. 171
      ext/bbcode/test.php
  49. 129
      ext/blocks/main.php
  50. 17
      ext/blocks/test.php
  51. 85
      ext/blocks/theme.php
  52. 241
      ext/blotter/main.php
  53. 58
      ext/blotter/test.php
  54. 270
      ext/blotter/theme.php
  55. 153
      ext/browser_search/main.php
  56. 13
      ext/browser_search/test.php
  57. 107
      ext/bulk_add/main.php
  58. 75
      ext/bulk_add/test.php
  59. 60
      ext/bulk_add/theme.php
  60. 232
      ext/bulk_add_csv/main.php
  61. 57
      ext/bulk_add_csv/theme.php
  62. 171
      ext/bulk_remove/main.php
  63. 401
      ext/chatbox/cp/ajax.php
  64. 8
      ext/chatbox/cp/index.php
  65. 165
      ext/chatbox/history/index.php
  66. 13
      ext/chatbox/include.php
  67. 28
      ext/chatbox/main.php
  68. 596
      ext/chatbox/php/ajaxcall.class.php
  69. 162
      ext/chatbox/php/filestorage.class.php
  70. 311
      ext/chatbox/php/functions.php
  71. 537
      ext/chatbox/php/yshout.class.php
  72. 123
      ext/chatbox/preferences.php
  73. 59
      ext/chatbox/yshout.php
  74. 1043
      ext/comment/main.php
  75. 217
      ext/comment/test.php
  76. 518
      ext/comment/theme.php
  77. 722
      ext/cron_uploader/main.php
  78. 100
      ext/custom_html_headers/main.php
  79. 637
      ext/danbooru_api/main.php
  80. 34
      ext/danbooru_api/test.php
  81. 64
      ext/downtime/main.php
  82. 77
      ext/downtime/test.php
  83. 50
      ext/downtime/theme.php
  84. 36
      ext/emoticons/main.php
  85. 27
      ext/emoticons/test.php
  86. 41
      ext/emoticons/theme.php
  87. 126
      ext/et/main.php
  88. 14
      ext/et/test.php
  89. 40
      ext/et/theme.php
  90. 373
      ext/ext_manager/main.php
  91. 38
      ext/ext_manager/test.php
  92. 201
      ext/ext_manager/theme.php
  93. 379
      ext/favorites/main.php
  94. 43
      ext/favorites/test.php
  95. 45
      ext/favorites/theme.php
  96. 132
      ext/featured/main.php
  97. 49
      ext/featured/test.php
  98. 37
      ext/featured/theme.php
  99. 711
      ext/forum/main.php
  100. 205
      ext/forum/theme.php
  101. Some files were not shown because too many files have changed in this diff Show More

@ -16,6 +16,6 @@ insert_final_newline = true
[*.{js,css,php}]
charset = utf-8
indent_style = tab
indent_style = space
indent_size = 4

1
.gitignore vendored

@ -4,6 +4,7 @@ images
thumbs
*.phar
*.sqlite
.php_cs.cache
#Composer
composer.phar

@ -0,0 +1,18 @@
<?php
$finder = PhpCsFixer\Finder::create()
->exclude('ext/amazon_s3/lib')
->exclude('vendor')
->in(__DIR__)
;
return PhpCsFixer\Config::create()
->setRules([
'@PSR2' => true,
//'strict_param' => true,
'array_syntax' => ['syntax' => 'short'],
])
->setFinder($finder)
;
?>

@ -19,14 +19,14 @@ _sanitise_environment();
// load base files
$_shm_ctx->log_start("Opening files");
$_shm_files = array_merge(
zglob("core/*.php"),
zglob("core/{".ENABLED_MODS."}/*.php"),
zglob("ext/{".ENABLED_EXTS."}/main.php")
zglob("core/*.php"),
zglob("core/{".ENABLED_MODS."}/*.php"),
zglob("ext/{".ENABLED_EXTS."}/main.php")
);
foreach($_shm_files as $_shm_filename) {
if(basename($_shm_filename)[0] != "_") {
require_once $_shm_filename;
}
foreach ($_shm_files as $_shm_filename) {
if (basename($_shm_filename)[0] != "_") {
require_once $_shm_filename;
}
}
unset($_shm_files);
unset($_shm_filename);
@ -40,8 +40,8 @@ $_shm_ctx->log_endok();
// load the theme parts
$_shm_ctx->log_start("Loading themelets");
foreach(_get_themelet_files(get_theme()) as $themelet) {
require_once $themelet;
foreach (_get_themelet_files(get_theme()) as $themelet) {
require_once $themelet;
}
unset($themelet);
$page = class_exists("CustomPage") ? new CustomPage() : new Page();

@ -7,7 +7,7 @@
* @author Shish [webmaster at shishnet.org], jgen [jeffgenovy at gmail.com]
* @link http://code.shishnet.org/shimmie2/
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*
* Initialise the database, check that folder
* permissions are set properly.
*
@ -30,7 +30,7 @@ date_default_timezone_set('UTC');
<script type="text/javascript" src="vendor/bower-asset/jquery/dist/jquery.min.js"></script>
</head>
<body>
<?php if(FALSE) { ?>
<?php if (false) { ?>
<div id="installer">
<h1>Install Error</h1>
<div class="container">
@ -43,7 +43,7 @@ date_default_timezone_set('UTC');
</div>
</div>
<pre style="display:none">
<?php } elseif(!file_exists("vendor/")) { ?>
<?php } elseif (!file_exists("vendor/")) { ?>
<div id="installer">
<h1>Install Error</h1>
<h3>Warning: Composer vendor folder does not exist!</h3>
@ -65,112 +65,114 @@ require_once "core/cacheengine.php";
require_once "core/dbengine.php";
require_once "core/database.php";
if(is_readable("data/config/shimmie.conf.php")) die("Shimmie is already installed.");
if (is_readable("data/config/shimmie.conf.php")) {
die("Shimmie is already installed.");
}
do_install();
// utilities {{{
// TODO: Can some of these be pushed into "core/???.inc.php" ?
function check_gd_version(): int {
$gdversion = 0;
if (function_exists('gd_info')){
$gd_info = gd_info();
if (substr_count($gd_info['GD Version'], '2.')) {
$gdversion = 2;
} else if (substr_count($gd_info['GD Version'], '1.')) {
$gdversion = 1;
}
}
return $gdversion;
// TODO: Can some of these be pushed into "core/???.inc.php" ?
function check_gd_version(): int
{
$gdversion = 0;
if (function_exists('gd_info')) {
$gd_info = gd_info();
if (substr_count($gd_info['GD Version'], '2.')) {
$gdversion = 2;
} elseif (substr_count($gd_info['GD Version'], '1.')) {
$gdversion = 1;
}
}
return $gdversion;
}
function check_im_version(): int {
$convert_check = exec("convert");
function check_im_version(): int
{
$convert_check = exec("convert");
return (empty($convert_check) ? 0 : 1);
return (empty($convert_check) ? 0 : 1);
}
function eok($name, $value) {
echo "<br>$name ... ";
if($value) {
echo "<span style='color: green'>ok</span>\n";
}
else {
echo "<span style='color: green'>failed</span>\n";
}
function eok($name, $value)
{
echo "<br>$name ... ";
if ($value) {
echo "<span style='color: green'>ok</span>\n";
} else {
echo "<span style='color: green'>failed</span>\n";
}
}
// }}}
function do_install() { // {{{
if(file_exists("data/config/auto_install.conf.php")) {
require_once "data/config/auto_install.conf.php";
}
else if(@$_POST["database_type"] == "sqlite") {
$id = bin2hex(random_bytes(5));
define('DATABASE_DSN', "sqlite:data/shimmie.{$id}.sqlite");
}
else if(isset($_POST['database_type']) && isset($_POST['database_host']) && isset($_POST['database_user']) && isset($_POST['database_name'])) {
define('DATABASE_DSN', "{$_POST['database_type']}:user={$_POST['database_user']};password={$_POST['database_password']};host={$_POST['database_host']};dbname={$_POST['database_name']}");
}
else {
ask_questions();
return;
}
define("CACHE_DSN", null);
define("DEBUG_SQL", false);
define("DATABASE_KA", true);
install_process();
function do_install()
{ // {{{
if (file_exists("data/config/auto_install.conf.php")) {
require_once "data/config/auto_install.conf.php";
} elseif (@$_POST["database_type"] == "sqlite") {
$id = bin2hex(random_bytes(5));
define('DATABASE_DSN', "sqlite:data/shimmie.{$id}.sqlite");
} elseif (isset($_POST['database_type']) && isset($_POST['database_host']) && isset($_POST['database_user']) && isset($_POST['database_name'])) {
define('DATABASE_DSN', "{$_POST['database_type']}:user={$_POST['database_user']};password={$_POST['database_password']};host={$_POST['database_host']};dbname={$_POST['database_name']}");
} else {
ask_questions();
return;
}
define("CACHE_DSN", null);
define("DEBUG_SQL", false);
define("DATABASE_KA", true);
install_process();
} // }}}
function ask_questions() { // {{{
$warnings = array();
$errors = array();
function ask_questions()
{ // {{{
$warnings = [];
$errors = [];
if(check_gd_version() == 0 && check_im_version() == 0) {
$errors[] = "
if (check_gd_version() == 0 && check_im_version() == 0) {
$errors[] = "
No thumbnailers could be found - install the imagemagick
tools (or the PHP-GD library, if imagemagick is unavailable).
";
}
else if(check_im_version() == 0) {
$warnings[] = "
} elseif (check_im_version() == 0) {
$warnings[] = "
The 'convert' command (from the imagemagick package)
could not be found - PHP-GD can be used instead, but
the size of thumbnails will be limited.
";
}
}
if(!function_exists('mb_strlen')) {
$errors[] = "
if (!function_exists('mb_strlen')) {
$errors[] = "
The mbstring PHP extension is missing - multibyte languages
(eg non-english languages) may not work right.
";
}
$drivers = PDO::getAvailableDrivers();
if(
!in_array("mysql", $drivers) &&
!in_array("pgsql", $drivers) &&
!in_array("sqlite", $drivers)
) {
$errors[] = "
}
$drivers = PDO::getAvailableDrivers();
if (
!in_array("mysql", $drivers) &&
!in_array("pgsql", $drivers) &&
!in_array("sqlite", $drivers)
) {
$errors[] = "
No database connection library could be found; shimmie needs
PDO with either Postgres, MySQL, or SQLite drivers
";
}
}
$db_m = in_array("mysql", $drivers) ? '<option value="mysql">MySQL</option>' : "";
$db_p = in_array("pgsql", $drivers) ? '<option value="pgsql">PostgreSQL</option>' : "";
$db_s = in_array("sqlite", $drivers) ? '<option value="sqlite">SQLite</option>' : "";
$db_m = in_array("mysql", $drivers) ? '<option value="mysql">MySQL</option>' : "";
$db_p = in_array("pgsql", $drivers) ? '<option value="pgsql">PostgreSQL</option>' : "";
$db_s = in_array("sqlite", $drivers) ? '<option value="sqlite">SQLite</option>' : "";
$warn_msg = $warnings ? "<h3>Warnings</h3>".implode("\n<p>", $warnings) : "";
$err_msg = $errors ? "<h3>Errors</h3>".implode("\n<p>", $errors) : "";
$warn_msg = $warnings ? "<h3>Warnings</h3>".implode("\n<p>", $warnings) : "";
$err_msg = $errors ? "<h3>Errors</h3>".implode("\n<p>", $errors) : "";
print <<<EOD
print <<<EOD
<div id="installer">
<h1>Shimmie Installer</h1>
@ -243,19 +245,21 @@ EOD;
/**
* This is where the install really takes place.
*/
function install_process() { // {{{
build_dirs();
create_tables();
insert_defaults();
write_config();
function install_process()
{ // {{{
build_dirs();
create_tables();
insert_defaults();
write_config();
} // }}}
function create_tables() { // {{{
try {
$db = new Database();
function create_tables()
{ // {{{
try {
$db = new Database();
if ( $db->count_tables() > 0 ) {
print <<<EOD
if ($db->count_tables() > 0) {
print <<<EOD
<div id="installer">
<h1>Shimmie Installer</h1>
<h3>Warning: The Database schema is not empty!</h3>
@ -266,22 +270,22 @@ function create_tables() { // {{{
</div>
</div>
EOD;
exit(2);
}
exit(2);
}
$db->create_table("aliases", "
$db->create_table("aliases", "
oldtag VARCHAR(128) NOT NULL,
newtag VARCHAR(128) NOT NULL,
PRIMARY KEY (oldtag)
");
$db->execute("CREATE INDEX aliases_newtag_idx ON aliases(newtag)", array());
$db->execute("CREATE INDEX aliases_newtag_idx ON aliases(newtag)", []);
$db->create_table("config", "
$db->create_table("config", "
name VARCHAR(128) NOT NULL,
value TEXT,
PRIMARY KEY (name)
");
$db->create_table("users", "
$db->create_table("users", "
id SCORE_AIPK,
name VARCHAR(32) UNIQUE NOT NULL,
pass VARCHAR(250),
@ -289,9 +293,9 @@ EOD;
class VARCHAR(32) NOT NULL DEFAULT 'user',
email VARCHAR(128)
");
$db->execute("CREATE INDEX users_name_idx ON users(name)", array());
$db->execute("CREATE INDEX users_name_idx ON users(name)", []);
$db->create_table("images", "
$db->create_table("images", "
id SCORE_AIPK,
owner_id INTEGER NOT NULL,
owner_ip SCORE_INET NOT NULL,
@ -306,69 +310,72 @@ EOD;
locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT
");
$db->execute("CREATE INDEX images_owner_id_idx ON images(owner_id)", array());
$db->execute("CREATE INDEX images_width_idx ON images(width)", array());
$db->execute("CREATE INDEX images_height_idx ON images(height)", array());
$db->execute("CREATE INDEX images_hash_idx ON images(hash)", array());
$db->execute("CREATE INDEX images_owner_id_idx ON images(owner_id)", []);
$db->execute("CREATE INDEX images_width_idx ON images(width)", []);
$db->execute("CREATE INDEX images_height_idx ON images(height)", []);
$db->execute("CREATE INDEX images_hash_idx ON images(hash)", []);
$db->create_table("tags", "
$db->create_table("tags", "
id SCORE_AIPK,
tag VARCHAR(64) UNIQUE NOT NULL,
count INTEGER NOT NULL DEFAULT 0
");
$db->execute("CREATE INDEX tags_tag_idx ON tags(tag)", array());
$db->execute("CREATE INDEX tags_tag_idx ON tags(tag)", []);
$db->create_table("image_tags", "
$db->create_table("image_tags", "
image_id INTEGER NOT NULL,
tag_id INTEGER NOT NULL,
UNIQUE(image_id, tag_id),
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
");
$db->execute("CREATE INDEX images_tags_image_id_idx ON image_tags(image_id)", array());
$db->execute("CREATE INDEX images_tags_tag_id_idx ON image_tags(tag_id)", array());
$db->execute("INSERT INTO config(name, value) VALUES('db_version', 11)");
$db->commit();
}
catch(PDOException $e) {
handle_db_errors(TRUE, "An error occurred while trying to create the database tables necessary for Shimmie.", $e->getMessage(), 3);
} catch (Exception $e) {
handle_db_errors(FALSE, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 4);
}
$db->execute("CREATE INDEX images_tags_image_id_idx ON image_tags(image_id)", []);
$db->execute("CREATE INDEX images_tags_tag_id_idx ON image_tags(tag_id)", []);
$db->execute("INSERT INTO config(name, value) VALUES('db_version', 11)");
$db->commit();
} catch (PDOException $e) {
handle_db_errors(true, "An error occurred while trying to create the database tables necessary for Shimmie.", $e->getMessage(), 3);
} catch (Exception $e) {
handle_db_errors(false, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 4);
}
} // }}}
function insert_defaults() { // {{{
try {
$db = new Database();
$db->execute("INSERT INTO users(name, pass, joindate, class) VALUES(:name, :pass, now(), :class)", Array("name" => 'Anonymous', "pass" => null, "class" => 'anonymous'));
$db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", Array("name" => 'anon_id', "value" => $db->get_last_insert_id('users_id_seq')));
if(check_im_version() > 0) {
$db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", Array("name" => 'thumb_engine', "value" => 'convert'));
}
$db->commit();
}
catch(PDOException $e) {
handle_db_errors(TRUE, "An error occurred while trying to insert data into the database.", $e->getMessage(), 5);
}
catch (Exception $e) {
handle_db_errors(FALSE, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 6);
}
function insert_defaults()
{ // {{{
try {
$db = new Database();
$db->execute("INSERT INTO users(name, pass, joindate, class) VALUES(:name, :pass, now(), :class)", ["name" => 'Anonymous', "pass" => null, "class" => 'anonymous']);
$db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", ["name" => 'anon_id', "value" => $db->get_last_insert_id('users_id_seq')]);
if (check_im_version() > 0) {
$db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", ["name" => 'thumb_engine', "value" => 'convert']);
}
$db->commit();
} catch (PDOException $e) {
handle_db_errors(true, "An error occurred while trying to insert data into the database.", $e->getMessage(), 5);
} catch (Exception $e) {
handle_db_errors(false, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 6);
}
} // }}}
function build_dirs() { // {{{
// *try* and make default dirs. Ignore any errors --
// if something is amiss, we'll tell the user later
if(!file_exists("data")) @mkdir("data");
if(!is_writable("data")) @chmod("data", 0755);
// Clear file status cache before checking again.
clearstatcache();
if(!file_exists("data") || !is_writable("data")) {
print "
function build_dirs()
{ // {{{
// *try* and make default dirs. Ignore any errors --
// if something is amiss, we'll tell the user later
if (!file_exists("data")) {
@mkdir("data");
}
if (!is_writable("data")) {
@chmod("data", 0755);
}
// Clear file status cache before checking again.
clearstatcache();
if (!file_exists("data") || !is_writable("data")) {
print "
<div id='installer'>
<h1>Shimmie Installer</h1>
<h3>Directory Permissions Error:</h3>
@ -381,22 +388,23 @@ function build_dirs() { // {{{
</div>
</div>
";
exit(7);
}
exit(7);
}
} // }}}
function write_config() { // {{{
$file_content = '<' . '?php' . "\n" .
"define('DATABASE_DSN', '".DATABASE_DSN."');\n" .
'?' . '>';
function write_config()
{ // {{{
$file_content = '<' . '?php' . "\n" .
"define('DATABASE_DSN', '".DATABASE_DSN."');\n" .
'?' . '>';
if(!file_exists("data/config")) {
mkdir("data/config", 0755, true);
}
if (!file_exists("data/config")) {
mkdir("data/config", 0755, true);
}
if(file_put_contents("data/config/shimmie.conf.php", $file_content, LOCK_EX)) {
header("Location: index.php");
print <<<EOD
if (file_put_contents("data/config/shimmie.conf.php", $file_content, LOCK_EX)) {
header("Location: index.php");
print <<<EOD
<div id="installer">
<h1>Shimmie Installer</h1>
<h3>Things are OK \o/</h3>
@ -405,10 +413,9 @@ function write_config() { // {{{
</div>
</div>
EOD;
}
else {
$h_file_content = htmlentities($file_content);
print <<<EOD
} else {
$h_file_content = htmlentities($file_content);
print <<<EOD
<div id="installer">
<h1>Shimmie Installer</h1>
<h3>File Permissions Error:</h3>
@ -425,13 +432,14 @@ EOD;
</div>
</div>
EOD;
}
echo "\n";
}
echo "\n";
} // }}}
function handle_db_errors(bool $isPDO, string $errorMessage1, string $errorMessage2, int $exitCode) {
$errorMessage1Extra = ($isPDO ? "Please check and ensure that the database configuration options are all correct." : "Please check the server log files for more information.");
print <<<EOD
function handle_db_errors(bool $isPDO, string $errorMessage1, string $errorMessage2, int $exitCode)
{
$errorMessage1Extra = ($isPDO ? "Please check and ensure that the database configuration options are all correct." : "Please check the server log files for more information.");
print <<<EOD
<div id="installer">
<h1>Shimmie Installer</h1>
<h3>Unknown Error:</h3>
@ -442,7 +450,7 @@ function handle_db_errors(bool $isPDO, string $errorMessage1, string $errorMessa
</div>
</div>
EOD;
exit($exitCode);
exit($exitCode);
}
?>
</body>

@ -5,117 +5,135 @@
*
* A collection of common functions for theme parts
*/
class BaseThemelet {
/**
* Generic error message display
*/
public function display_error(int $code, string $title, string $message): void {
global $page;
$page->set_code($code);
$page->set_title($title);
$page->set_heading($title);
$has_nav = false;
foreach($page->blocks as $block) {
if($block->header == "Navigation") {
$has_nav = true;
break;
}
}
if(!$has_nav) {
$page->add_block(new NavBlock());
}
$page->add_block(new Block("Error", $message));
}
/**
* A specific, common error message
*/
public function display_permission_denied(): void {
$this->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
/**
* Generic thumbnail code; returns HTML rather than adding
* a block since thumbs tend to go inside blocks...
*/
public function build_thumb_html(Image $image): string {
global $config;
$i_id = (int) $image->id;
$h_view_link = make_link('post/view/'.$i_id);
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$h_tags = html_escape(strtolower($image->get_tag_list()));
$extArr = array_flip(array('swf', 'svg', 'mp3')); //List of thumbless filetypes
if(!isset($extArr[$image->ext])){
$tsize = get_thumbnail_size($image->width, $image->height);
}else{
//Use max thumbnail size if using thumbless filetype
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
}
$custom_classes = "";
if(class_exists("Relationships")){
if(property_exists($image, 'parent_id') && $image->parent_id !== NULL){ $custom_classes .= "shm-thumb-has_parent "; }
if(property_exists($image, 'has_children') && bool_escape($image->has_children)){ $custom_classes .= "shm-thumb-has_child "; }
}
return "<a href='$h_view_link' class='thumb shm-thumb shm-thumb-link {$custom_classes}' data-tags='$h_tags' data-post-id='$i_id'>".
"<img id='thumb_$i_id' title='$h_tip' alt='$h_tip' height='{$tsize[1]}' width='{$tsize[0]}' src='$h_thumb_link'>".
"</a>\n";
}
public function display_paginator(Page $page, string $base, string $query=null, int $page_number, int $total_pages, bool $show_random = FALSE) {
if($total_pages == 0) $total_pages = 1;
$body = $this->build_paginator($page_number, $total_pages, $base, $query, $show_random);
$page->add_block(new Block(null, $body, "main", 90, "paginator"));
}
private function gen_page_link(string $base_url, string $query=null, string $page, string $name): string {
$link = make_link($base_url.'/'.$page, $query);
return '<a href="'.$link.'">'.$name.'</a>';
}
private function gen_page_link_block(string $base_url, string $query=null, string $page, int $current_page, string $name): string {
$paginator = "";
if($page == $current_page) $paginator .= "<b>";
$paginator .= $this->gen_page_link($base_url, $query, $page, $name);
if($page == $current_page) $paginator .= "</b>";
return $paginator;
}
private function build_paginator(int $current_page, int $total_pages, string $base_url, string $query=null, bool $show_random): string {
$next = $current_page + 1;
$prev = $current_page - 1;
$at_start = ($current_page <= 1 || $total_pages <= 1);
$at_end = ($current_page >= $total_pages);
$first_html = $at_start ? "First" : $this->gen_page_link($base_url, $query, 1, "First");
$prev_html = $at_start ? "Prev" : $this->gen_page_link($base_url, $query, $prev, "Prev");
$random_html = "-";
if($show_random) {
$rand = mt_rand(1, $total_pages);
$random_html = $this->gen_page_link($base_url, $query, $rand, "Random");
}
$next_html = $at_end ? "Next" : $this->gen_page_link($base_url, $query, $next, "Next");
$last_html = $at_end ? "Last" : $this->gen_page_link($base_url, $query, $total_pages, "Last");
$start = $current_page-5 > 1 ? $current_page-5 : 1;
$end = $start+10 < $total_pages ? $start+10 : $total_pages;
$pages = array();
foreach(range($start, $end) as $i) {
$pages[] = $this->gen_page_link_block($base_url, $query, $i, $current_page, $i);
}
$pages_html = implode(" | ", $pages);
return $first_html.' | '.$prev_html.' | '.$random_html.' | '.$next_html.' | '.$last_html
.'<br>&lt;&lt; '.$pages_html.' &gt;&gt;';
}
class BaseThemelet
{
/**
* Generic error message display
*/
public function display_error(int $code, string $title, string $message): void
{
global $page;
$page->set_code($code);
$page->set_title($title);
$page->set_heading($title);
$has_nav = false;
foreach ($page->blocks as $block) {
if ($block->header == "Navigation") {
$has_nav = true;
break;
}
}
if (!$has_nav) {
$page->add_block(new NavBlock());
}
$page->add_block(new Block("Error", $message));
}
/**
* A specific, common error message
*/
public function display_permission_denied(): void
{
$this->display_error(403, "Permission Denied", "You do not have permission to access this page");
}
/**
* Generic thumbnail code; returns HTML rather than adding
* a block since thumbs tend to go inside blocks...
*/
public function build_thumb_html(Image $image): string
{
global $config;
$i_id = (int) $image->id;
$h_view_link = make_link('post/view/'.$i_id);
$h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip());
$h_tags = html_escape(strtolower($image->get_tag_list()));
$extArr = array_flip(['swf', 'svg', 'mp3']); //List of thumbless filetypes
if (!isset($extArr[$image->ext])) {
$tsize = get_thumbnail_size($image->width, $image->height);
} else {
//Use max thumbnail size if using thumbless filetype
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
}
$custom_classes = "";
if (class_exists("Relationships")) {
if (property_exists($image, 'parent_id') && $image->parent_id !== null) {
$custom_classes .= "shm-thumb-has_parent ";
}
if (property_exists($image, 'has_children') && bool_escape($image->has_children)) {
$custom_classes .= "shm-thumb-has_child ";
}
}
return "<a href='$h_view_link' class='thumb shm-thumb shm-thumb-link {$custom_classes}' data-tags='$h_tags' data-post-id='$i_id'>".
"<img id='thumb_$i_id' title='$h_tip' alt='$h_tip' height='{$tsize[1]}' width='{$tsize[0]}' src='$h_thumb_link'>".
"</a>\n";
}
public function display_paginator(Page $page, string $base, string $query=null, int $page_number, int $total_pages, bool $show_random = false)
{
if ($total_pages == 0) {
$total_pages = 1;
}
$body = $this->build_paginator($page_number, $total_pages, $base, $query, $show_random);
$page->add_block(new Block(null, $body, "main", 90, "paginator"));
}
private function gen_page_link(string $base_url, string $query=null, string $page, string $name): string
{
$link = make_link($base_url.'/'.$page, $query);
return '<a href="'.$link.'">'.$name.'</a>';
}
private function gen_page_link_block(string $base_url, string $query=null, string $page, int $current_page, string $name): string
{
$paginator = "";
if ($page == $current_page) {
$paginator .= "<b>";
}
$paginator .= $this->gen_page_link($base_url, $query, $page, $name);
if ($page == $current_page) {
$paginator .= "</b>";
}
return $paginator;
}
private function build_paginator(int $current_page, int $total_pages, string $base_url, string $query=null, bool $show_random): string
{
$next = $current_page + 1;
$prev = $current_page - 1;
$at_start = ($current_page <= 1 || $total_pages <= 1);
$at_end = ($current_page >= $total_pages);
$first_html = $at_start ? "First" : $this->gen_page_link($base_url, $query, 1, "First");
$prev_html = $at_start ? "Prev" : $this->gen_page_link($base_url, $query, $prev, "Prev");
$random_html = "-";
if ($show_random) {
$rand = mt_rand(1, $total_pages);
$random_html = $this->gen_page_link($base_url, $query, $rand, "Random");
}
$next_html = $at_end ? "Next" : $this->gen_page_link($base_url, $query, $next, "Next");
$last_html = $at_end ? "Last" : $this->gen_page_link($base_url, $query, $total_pages, "Last");
$start = $current_page-5 > 1 ? $current_page-5 : 1;
$end = $start+10 < $total_pages ? $start+10 : $total_pages;
$pages = [];
foreach (range($start, $end) as $i) {
$pages[] = $this->gen_page_link_block($base_url, $query, $i, $current_page, $i);
}
$pages_html = implode(" | ", $pages);
return $first_html.' | '.$prev_html.' | '.$random_html.' | '.$next_html.' | '.$last_html
.'<br>&lt;&lt; '.$pages_html.' &gt;&gt;';
}
}

@ -5,79 +5,86 @@
*
* A basic chunk of a page.
*/
class Block {
/**
* The block's title.
*
* @var string
*/
public $header;
class Block
{
/**
* The block's title.
*
* @var string
*/
public $header;
/**
* The content of the block.
*
* @var string
*/
public $body;
/**
* The content of the block.
*
* @var string
*/
public $body;
/**
* Where the block should be placed. The default theme supports
* "main" and "left", other themes can add their own areas.
*
* @var string
*/
public $section;
/**
* Where the block should be placed. The default theme supports
* "main" and "left", other themes can add their own areas.
*
* @var string
*/
public $section;
/**
* How far down the section the block should appear, higher
* numbers appear lower. The scale is 0-100 by convention,
* though any number or string will work.
*
* @var int
*/
public $position;
/**
* How far down the section the block should appear, higher
* numbers appear lower. The scale is 0-100 by convention,
* though any number or string will work.
*
* @var int
*/
public $position;
/**
* A unique ID for the block.
*
* @var string
*/
public $id;
/**
* A unique ID for the block.
*
* @var string
*/
public $id;
/**
* Should this block count as content for the sake of
* the 404 handler
*
* @var boolean
*/
public $is_content = true;
/**
* Should this block count as content for the sake of
* the 404 handler
*
* @var boolean
*/
public $is_content = true;
public function __construct(string $header=null, string $body=null, string $section="main", int $position=50, string $id=null) {
$this->header = $header;
$this->body = $body;
$this->section = $section;
$this->position = $position;
public function __construct(string $header=null, string $body=null, string $section="main", int $position=50, string $id=null)
{
$this->header = $header;
$this->body = $body;
$this->section = $section;
$this->position = $position;
if(is_null($id)) {
$id = (empty($header) ? md5($body) : $header) . $section;
}
$this->id = preg_replace('/[^\w]/', '',str_replace(' ', '_', $id));
}
if (is_null($id)) {
$id = (empty($header) ? md5($body) : $header) . $section;
}
$this->id = preg_replace('/[^\w]/', '', str_replace(' ', '_', $id));
}
/**
* Get the HTML for this block.
*/
public function get_html(bool $hidable=false): string {
$h = $this->header;
$b = $this->body;
$i = $this->id;
$html = "<section id='$i'>";
$h_toggler = $hidable ? " shm-toggler" : "";
if(!empty($h)) $html .= "<h3 data-toggle-sel='#$i' class='$h_toggler'>$h</h3>";
if(!empty($b)) $html .= "<div class='blockbody'>$b</div>";
$html .= "</section>\n";
return $html;
}
/**
* Get the HTML for this block.
*/
public function get_html(bool $hidable=false): string
{
$h = $this->header;
$b = $this->body;
$i = $this->id;
$html = "<section id='$i'>";
$h_toggler = $hidable ? " shm-toggler" : "";
if (!empty($h)) {
$html .= "<h3 data-toggle-sel='#$i' class='$h_toggler'>$h</h3>";
}
if (!empty($b)) {
$html .= "<div class='blockbody'>$b</div>";
}
$html .= "</section>\n";
return $html;
}
}
@ -89,8 +96,10 @@ class Block {
* Used because "new NavBlock()" is easier than "new Block('Navigation', ..."
*
*/
class NavBlock extends Block {
public function __construct() {
parent::__construct("Navigation", "<a href='".make_link()."'>Index</a>", "left", 0);
}
class NavBlock extends Block
{
public function __construct()
{
parent::__construct("Navigation", "<a href='".make_link()."'>Index</a>", "left", 0);
}
}

@ -1,196 +1,228 @@
<?php
interface CacheEngine {
public function get(string $key);
public function set(string $key, $val, int $time=0);
public function delete(string $key);
interface CacheEngine
{
public function get(string $key);
public function set(string $key, $val, int $time=0);
public function delete(string $key);
}
class NoCache implements CacheEngine {
public function get(string $key) {return false;}
public function set(string $key, $val, int $time=0) {}
public function delete(string $key) {}
class NoCache implements CacheEngine
{
public function get(string $key)
{
return false;
}
public function set(string $key, $val, int $time=0)
{
}
public function delete(string $key)
{
}
}
class MemcacheCache implements CacheEngine {
/** @var \Memcache|null */
public $memcache=null;
public function __construct(string $args) {
$hp = explode(":", $args);
$this->memcache = new Memcache;
@$this->memcache->pconnect($hp[0], $hp[1]);
}
public function get(string $key) {
return $this->memcache->get($key);
}
public function set(string $key, $val, int $time=0) {
$this->memcache->set($key, $val, false, $time);
}
public function delete(string $key) {
$this->memcache->delete($key);
}
class MemcacheCache implements CacheEngine
{
/** @var \Memcache|null */
public $memcache=null;
public function __construct(string $args)
{
$hp = explode(":", $args);
$this->memcache = new Memcache;
@$this->memcache->pconnect($hp[0], $hp[1]);
}
public function get(string $key)
{
return $this->memcache->get($key);
}
public function set(string $key, $val, int $time=0)
{
$this->memcache->set($key, $val, false, $time);
}
public function delete(string $key)
{
$this->memcache->delete($key);
}
}
class MemcachedCache implements CacheEngine {
/** @var \Memcached|null */
public $memcache=null;
public function __construct(string $args) {
$hp = explode(":", $args);
$this->memcache = new Memcached;
#$this->memcache->setOption(Memcached::OPT_COMPRESSION, False);
#$this->memcache->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP);
#$this->memcache->setOption(Memcached::OPT_PREFIX_KEY, phpversion());
$this->memcache->addServer($hp[0], $hp[1]);
}
public function get(string $key) {
$key = urlencode($key);
$val = $this->memcache->get($key);
$res = $this->memcache->getResultCode();
if($res == Memcached::RES_SUCCESS) {
return $val;
}
else if($res == Memcached::RES_NOTFOUND) {
return false;
}
else {
error_log("Memcached error during get($key): $res");
return false;
}
}
public function set(string $key, $val, int $time=0) {
$key = urlencode($key);
$this->memcache->set($key, $val, $time);
$res = $this->memcache->getResultCode();
if($res != Memcached::RES_SUCCESS) {
error_log("Memcached error during set($key): $res");
}
}
public function delete(string $key) {
$key = urlencode($key);
$this->memcache->delete($key);
$res = $this->memcache->getResultCode();
if($res != Memcached::RES_SUCCESS && $res != Memcached::RES_NOTFOUND) {
error_log("Memcached error during delete($key): $res");
}
}
class MemcachedCache implements CacheEngine
{
/** @var \Memcached|null */
public $memcache=null;
public function __construct(string $args)
{
$hp = explode(":", $args);
$this->memcache = new Memcached;
#$this->memcache->setOption(Memcached::OPT_COMPRESSION, False);
#$this->memcache->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP);
#$this->memcache->setOption(Memcached::OPT_PREFIX_KEY, phpversion());
$this->memcache->addServer($hp[0], $hp[1]);
}
public function get(string $key)
{
$key = urlencode($key);
$val = $this->memcache->get($key);
$res = $this->memcache->getResultCode();
if ($res == Memcached::RES_SUCCESS) {
return $val;
} elseif ($res == Memcached::RES_NOTFOUND) {
return false;
} else {
error_log("Memcached error during get($key): $res");
return false;
}
}
public function set(string $key, $val, int $time=0)
{
$key = urlencode($key);
$this->memcache->set($key, $val, $time);
$res = $this->memcache->getResultCode();
if ($res != Memcached::RES_SUCCESS) {
error_log("Memcached error during set($key): $res");
}
}
public function delete(string $key)
{
$key = urlencode($key);
$this->memcache->delete($key);
$res = $this->memcache->getResultCode();
if ($res != Memcached::RES_SUCCESS && $res != Memcached::RES_NOTFOUND) {
error_log("Memcached error during delete($key): $res");
}
}
}
class APCCache implements CacheEngine {
public function __construct(string $args) {
// $args is not used, but is passed in when APC cache is created.
}
public function get(string $key) {
return apc_fetch($key);
}
public function set(string $key, $val, int $time=0) {
apc_store($key, $val, $time);
}
public function delete(string $key) {
apc_delete($key);
}
class APCCache implements CacheEngine
{
public function __construct(string $args)
{
// $args is not used, but is passed in when APC cache is created.
}
public function get(string $key)
{
return apc_fetch($key);
}
public function set(string $key, $val, int $time=0)
{
apc_store($key, $val, $time);
}
public function delete(string $key)
{
apc_delete($key);
}
}
class RedisCache implements CacheEngine {
private $redis=null;
public function __construct(string $args) {
$this->redis = new Redis();
$hp = explode(":", $args);
$this->redis->pconnect($hp[0], $hp[1]);
$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$this->redis->setOption(Redis::OPT_PREFIX, 'shm:');
}
public function get(string $key) {
return $this->redis->get($key);
}
public function set(string $key, $val, int $time=0) {
if($time > 0) {
$this->redis->setEx($key, $time, $val);
}
else {
$this->redis->set($key, $val);
}
}
public function delete(string $key) {
$this->redis->delete($key);
}
class RedisCache implements CacheEngine
{
private $redis=null;
public function __construct(string $args)
{
$this->redis = new Redis();
$hp = explode(":", $args);
$this->redis->pconnect($hp[0], $hp[1]);
$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$this->redis->setOption(Redis::OPT_PREFIX, 'shm:');
}
public function get(string $key)
{
return $this->redis->get($key);
}
public function set(string $key, $val, int $time=0)
{
if ($time > 0) {
$this->redis->setEx($key, $time, $val);
} else {
$this->redis->set($key, $val);
}
}
public function delete(string $key)
{
$this->redis->delete($key);
}
}
class Cache {
public $engine;
public $hits=0, $misses=0;
public $time=0;
public function __construct(?string $dsn) {
$matches = array();
if($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches)) {
if($matches[1] == "memcache") {
$c = new MemcacheCache($matches[2]);
}
else if($matches[1] == "memcached") {
$c = new MemcachedCache($matches[2]);
}
else if($matches[1] == "apc") {
$c = new APCCache($matches[2]);
}
else if($matches[1] == "redis") {
$c = new RedisCache($matches[2]);
}
}
else {
$c = new NoCache();
}
$this->engine = $c;
}
public function get(string $key) {
$val = $this->engine->get($key);
if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) {
$hit = $val === false ? "hit" : "miss";
file_put_contents("data/cache.log", "Cache $hit: $key\n", FILE_APPEND);
}
if($val !== false) {
$this->hits++;
return $val;
}
else {
$this->misses++;
return false;
}
}
public function set(string $key, $val, int $time=0) {
$this->engine->set($key, $val, $time);
if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) {
file_put_contents("data/cache.log", "Cache set: $key ($time)\n", FILE_APPEND);
}
}
public function delete(string $key) {
$this->engine->delete($key);
if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) {
file_put_contents("data/cache.log", "Cache delete: $key\n", FILE_APPEND);
}
}
public function get_hits(): int {return $this->hits;}
public function get_misses(): int {return $this->misses;}
class Cache
{
public $engine;
public $hits=0;
public $misses=0;
public $time=0;
public function __construct(?string $dsn)
{
$matches = [];
if ($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches)) {
if ($matches[1] == "memcache") {
$c = new MemcacheCache($matches[2]);
} elseif ($matches[1] == "memcached") {
$c = new MemcachedCache($matches[2]);
} elseif ($matches[1] == "apc") {
$c = new APCCache($matches[2]);
} elseif ($matches[1] == "redis") {
$c = new RedisCache($matches[2]);
}
} else {
$c = new NoCache();
}
$this->engine = $c;
}
public function get(string $key)
{
$val = $this->engine->get($key);
if ((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) {
$hit = $val === false ? "hit" : "miss";
file_put_contents("data/cache.log", "Cache $hit: $key\n", FILE_APPEND);
}
if ($val !== false) {
$this->hits++;
return $val;
} else {
$this->misses++;
return false;
}
}
public function set(string $key, $val, int $time=0)
{
$this->engine->set($key, $val, $time);
if ((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) {
file_put_contents("data/cache.log", "Cache set: $key ($time)\n", FILE_APPEND);
}
}
public function delete(string $key)
{
$this->engine->delete($key);
if ((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) {
file_put_contents("data/cache.log", "Cache delete: $key\n", FILE_APPEND);
}
}
public function get_hits(): int
{
return $this->hits;
}
public function get_misses(): int
{
return $this->misses;
}
}

@ -3,53 +3,56 @@
* CAPTCHA abstraction *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
function captcha_get_html(): string {
global $config, $user;
if(DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) return "";
$captcha = "";
if($user->is_anonymous() && $config->get_bool("comment_captcha")) {
$r_publickey = $config->get_string("api_recaptcha_pubkey");
if(!empty($r_publickey)) {
$captcha = "
function captcha_get_html(): string
{
global $config, $user;
if (DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) {
return "";
}
$captcha = "";
if ($user->is_anonymous() && $config->get_bool("comment_captcha")) {
$r_publickey = $config->get_string("api_recaptcha_pubkey");
if (!empty($r_publickey)) {
$captcha = "
<div class=\"g-recaptcha\" data-sitekey=\"{$r_publickey}\"></div>
<script type=\"text/javascript\" src=\"https://www.google.com/recaptcha/api.js\"></script>";
} else {
session_start();
$captcha = Securimage::getCaptchaHtml(['securimage_path' => './vendor/dapphp/securimage/']);
}
}
return $captcha;
} else {
session_start();
$captcha = Securimage::getCaptchaHtml(['securimage_path' => './vendor/dapphp/securimage/']);
}
}
return $captcha;
}
function captcha_check(): bool {
global $config, $user;
if(DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) return true;
if($user->is_anonymous() && $config->get_bool("comment_captcha")) {
$r_privatekey = $config->get_string('api_recaptcha_privkey');
if(!empty($r_privatekey)) {
$recaptcha = new \ReCaptcha\ReCaptcha($r_privatekey);
$resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
if(!$resp->isSuccess()) {
log_info("core", "Captcha failed (ReCaptcha): " . implode("", $resp->getErrorCodes()));
return false;
}
}
else {
session_start();
$securimg = new Securimage();
if($securimg->check($_POST['captcha_code']) === false) {
log_info("core", "Captcha failed (Securimage)");
return false;
}
}
}
return true;
function captcha_check(): bool
{
global $config, $user;
if (DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) {
return true;
}
if ($user->is_anonymous() && $config->get_bool("comment_captcha")) {
$r_privatekey = $config->get_string('api_recaptcha_privkey');
if (!empty($r_privatekey)) {
$recaptcha = new \ReCaptcha\ReCaptcha($r_privatekey);
$resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
if (!$resp->isSuccess()) {
log_info("core", "Captcha failed (ReCaptcha): " . implode("", $resp->getErrorCodes()));
return false;
}
} else {
session_start();
$securimg = new Securimage();
if ($securimg->check($_POST['captcha_code']) === false) {
log_info("core", "Captcha failed (Securimage)");
return false;
}
}
}
return true;
}

@ -5,100 +5,101 @@
*
* An abstract interface for altering a name:value pair list.