Mercurial > hg > mgallery
view mgallery.inc.php @ 328:2e9326abe254
Adjustments to CSS.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 11 Feb 2022 19:40:05 +0200 |
parents | 782c1520984e |
children | 14d3741061f5 |
line wrap: on
line source
<?php // // Yet Another Image Gallery // -- Common functions and data include // Programmed and designed by Matti 'ccr' Hamalainen <ccr@tnsp.org> // (C) Copyright 2015-2022 Tecnic Software productions (TNSP) // $mgProgVersion = "v0.9.12"; $mgProgInfo = "Programmed by Matti 'ccr' Hamalainen"; $mgProgEmail = "<ccr@tnsp.org>"; $mgProgCopyright = "2015-2022 Tecnic Software productions (TNSP)"; $mgProgConfigFile = "mgallery.cfg"; $mgalDebug = FALSE; // // Navigation control defines // define("MGF_JAVASCRIPT" , 0x01); define("MGF_BREADCRUMBS" , 0x10); define("MGF_CAPTIONS" , 0x20); // // Constants for different value types // define("MG_STR" , 1); define("MG_STR_LC" , 2); define("MG_STR_ARRAY" , 3); define("MG_INT" , 4); define("MG_DVA" , 5); define("MG_BOOL" , 6); define("MG_FLAGS" , 7); define("MG_DATE" , 8); define("yes" , 1); define("no" , 0); $mgGFlags = [ "javascript" => MGF_JAVASCRIPT, "breadcrumbs" => MGF_BREADCRUMBS, "captions" => MGF_CAPTIONS, ]; function mgPathName($path) { $tmp = mgCleanPathArray(TRUE, 0, func_num_args(), func_get_args()); if (count($tmp) > 0) return implode("/", array_splice($tmp, 0, -1))."/"; else return $path; } // // Configuration settings and their default values // $mgDefaults = [ "timezone" => [MG_STR, NULL], "clean_urls" => [MG_BOOL, FALSE], "base_path" => [MG_STR, mgPathName(mgRealPath($_SERVER["SCRIPT_FILENAME"]))], "base_url" => [MG_STR, mgPathName($_SERVER["PHP_SELF"])], "image_url" => [MG_STR, mgPathName($_SERVER["PHP_SELF"])], "mgallery_php" => [MG_STR, ""], "format_exts" => [MG_STR, "\.jpg|\.png|\.gif|\.jpeg|\.webp"], "captions_file" => [MG_STR, "captions.txt"], "header_file" => [MG_STR, "header.txt"], "info_file" => [MG_STR, "mgallery.info"], "cache_file" => [MG_STR, ".mgallery.cache"], "cover_images" => [MG_BOOL, TRUE], "album_icon" => [MG_STR, NULL], "title_prefix" => [MG_STR, ""], "title_sep" => [MG_STR, " - "], "page_info" => [MG_STR, "Powered by <b>MGallery ".$mgProgVersion."</b> © Copyright ".$mgProgCopyright], "css" => [MG_STR_ARRAY, NULL], "js_file" => [MG_STR_ARRAY, NULL], "urchin_file" => [MG_STR_ARRAY, FALSE], "global_flags" => [MG_FLAGS, MGF_JAVASCRIPT | MGF_BREADCRUMBS | MGF_CAPTIONS, &$mgGFlags], "image_flags" => [MG_FLAGS, MGF_JAVASCRIPT | MGF_BREADCRUMBS, &$mgGFlags], "album_flags" => [MG_FLAGS, MGF_JAVASCRIPT | MGF_BREADCRUMBS, &$mgGFlags], "tn_path" => [MG_STR, "tn/"], "med_path" => [MG_STR, "med/"], "tn_format" => [MG_STR_LC, "jpeg"], "tn_width" => [MG_INT, 140], // In pixels, applies as bounding box for w/h "tn_height" => [MG_INT, 100], "tn_quality" => [MG_INT, 90], // JPEG/WEBP quality percent "med_format" => [MG_STR_LC, "jpeg"], "med_width" => [MG_INT, 1200], "med_height" => [MG_INT, 900], "med_quality" => [MG_INT, 90], "backend" => [MG_STR_LC, "php"], "sql_db" => [MG_STR, FALSE], "sql_username" => [MG_STR, ""], "sql_password" => [MG_STR, ""], "sql_options" => [MG_STR_ARRAY, []], ]; function mgDebug($msg) { global $mgalDebug; if ($mgalDebug) { echo "<p>MGAL[debug]: ".htmlspecialchars($msg)."</p>"; error_log("MGAL[debug]: ".$msg); } } function mgFatal($msg) { die("MGAL[fatal]: ".$msg); } function mgError($msg) { error_log("MGAL[error]: ".$msg); return FALSE; } function mgCArg($index, $clip = FALSE) { global $argc, $argv; if ($index < $argc) { $str = $argv[$index]; return ($clip !== FALSE) ? substr($str, 0, $clip) : $str; } else return FALSE; } function mgCArgLC($index, $clip = FALSE) { global $argc, $argv; if ($index < $argc) { $str = strtolower($argv[$index]); return ($clip !== FALSE) ? substr($str, 0, $clip) : $str; } else return FALSE; } function mgGetSetting($key, $default = NULL) { global $mgSettings, $mgDefaults; if (!array_key_exists($key, $mgDefaults)) mgFatal("Setting '".$key."' does not exist.\n"); if (array_key_exists($key, $mgSettings)) $val = $mgSettings[$key]; else $val = $mgDefaults[$key][1]; if (!isset($val) || $val === NULL) { if ($default !== NULL) $val = $default; else mgFatal("Setting '".$key."' is not set, but is required to be configured.\n"); } switch ($mgDefaults[$key][0]) { case MG_STR_LC: $val = strtolower($val); break; case MG_FLAGS: if (is_string($val)) { $flags = $mgDefaults[$key][2]; $cval = preg_split("/\s*[,|]\s*/", strtolower($val), -1, PREG_SPLIT_NO_EMPTY); $nval = 0; foreach ($cval as $qval) { if (array_key_exists($qval, $flags)) $nval |= $flags[$qval]; else mgFatal("Invalid flag value for '".$key."': '".$qval."'."); } } break; } return $val; } function mgGetAlbumSetting(&$data, $key, $default = NULL) { if (array_key_exists($key, $data)) $val = $data[$key]; else $val = mgGetSetting($key, $default); // XXX This is a rather silly place for this check, but since any album can // set their own formats, we can't do this check globally without scanning // all the sub-albums etc .. maybe we'll do that some day. if (($key == "tn_format" || $key == "med_format") && $val == "webp" && version_compare(PHP_VERSION, "7.1.0") < 0) { mgFatal("WebP image format support requires PHP version 7.1 or later.\n"); } return $val; } function mgGetPath($path, $key) { $val = mgGetSetting($key); return ($val !== FALSE) ? $path."/".$val : FALSE; } function mgReadOneConfig(&$searchPaths, $pathList) { global $mgSettings, $mgProgConfigFile; $found = FALSE; foreach (array_unique($pathList) as $path) { $filename = $path.$mgProgConfigFile; $searchPaths[] = $filename; if (!$found) { mgDebug("Checking '".$filename."' for configuration ..\n"); if (file_exists($filename) && ($data = parse_ini_file($filename, FALSE)) !== FALSE) { mgDebug("Found '".$filename."' config.\n"); foreach ($data as $dkey => &$dval) $mgSettings[$dkey] = $dval; $found = TRUE; } } } return $found; } function mgReadSettings(&$searchPaths) { global $mgSettings; $mgSettings = []; $searchPaths = []; // System-wide $ok = mgReadOneConfig($searchPaths, ["/etc/", "/usr/local/etc/"]); // User-specific $spaths = []; if (($tmp = getenv("HOME")) !== FALSE && strlen($tmp) > 0) { $spaths[] = $tmp."/.config/mgallery/"; $spaths[] = $tmp."/."; } else { $data = posix_getpwuid(posix_getuid()); if ($data !== FALSE && isset($data["dir"])) { $tmp = $data["dir"]; $spaths[] = $tmp."/.config/mgallery/"; $spaths[] = $tmp."/."; } } $ok |= mgReadOneConfig($searchPaths, $spaths); // Album/directory-local $ok |= mgReadOneConfig($searchPaths, [ dirname(__FILE__)."/", getcwd()."/" ]); $searchPaths = array_unique($searchPaths); return $ok; } function mgRealPath($path) { return realpath($path); } function mgCleanPathStr($path) { return str_replace("//", "/", $path); } function mgCleanPathArray($refs, $start, $argc, $argv) { $path = []; $first = TRUE; for ($n = $start; $n < $argc; $n++) { foreach (explode("/", $argv[$n]) as $piece) { switch ($piece) { case ".": case "": if ($first) $path[] = $piece; break; case "..": if ($refs && count($path) > 0) array_pop($path); break; default: $path[] = $piece; break; } $first = FALSE; } } return mgCleanPathStr($path); } function mgCleanPath($refs) { return implode("/", mgCleanPathArray($refs, 1, func_num_args(), func_get_args())); } function mgGetArr($data, $skeys, $sfmt1 = "%1", $sfmt2 = "", $func = NULL) { global $pageLang; if (!is_array($skeys)) $skeys = array($skeys); foreach ($skeys as $skey) if (!array_key_exists($skey, $data)) return $sfmt2; $str = $sfmt1; for ($i = 1; $i <= sizeof($skeys); $i++) { $val = $data[$skeys[$i - 1]]; if (is_array($val)) $vtmp = array_key_exists($pageLang, $val) ? $val[$pageLang] : reset($val); else $vtmp = $val; if (is_callable($func)) $vtmp = call_user_func($func, $vtmp); $str = str_replace("%".$i, $vtmp, $str); } return $str; } function mgLogSQLError($dbh, $sql) { return mgError("SQL error '".implode("; ", $dbh->errorInfo())."' in statement: \"".$sql."\""); } function mgDBGetSQLParam($dbh, $type, $value) { switch ($type) { case "d": return intval($value); case "s": return $dbh->quote($value); case "b": return intval($value) ? 1 : 0; case "D": if ($value instanceOf DateTime) { switch ($dbh->getAttribute(PDO::ATTR_DRIVER_NAME)) { case "pgsql" : $fmt = "Y-m-d H:i:sP"; break; case "sqlite" : $fmt = DATE_RFC3339; break; case "mysql" : $fmt = "Y-m-d H:i:s"; break; default : $fmt = DATE_RFC3339; } return $dbh->quote($value->format($fmt)); } else return intval($value); } } function mgSQLToDateTime($dbh, $stamp) { switch ($dbh->getAttribute(PDO::ATTR_DRIVER_NAME)) { case "pgsql": // PostgreSQL 'timestamptz' format $tmp = DateTime::createFromFormat("Y-m-d H:i:sP", $stamp); break; case "sqlite": // SQLite can use RFC3339 format $tmp = DateTime::createFromFormat(DATE_RFC3339, $stamp); break; case "mysql": // MySQL uses UTC internally, no way to specify TZ $tmp = DateTime::createFromFormat("Y-m-d H:i:s", $stamp); break; default: $tmp = NULL; } // echo "<p>".$stamp." :: ".var_export(($tmp instanceOf DateTime) ? $tmp : NULL, TRUE)."</p>"; return ($tmp instanceOf DateTime) ? $tmp : NULL; } function mgConnectSQLDB() { global $db; try { $db = new PDO(mgGetSetting("sql_db"), mgGetSetting("sql_username", NULL), mgGetSetting("sql_password", NULL), mgGetSetting("sql_options", array())); } catch (PDOException $e) { mgError("Could not connect to SQL database: ".$e->getMessage()."."); return FALSE; } return ($db !== false); } function mgDBPrepareSQLUpdate($dbh, $table, $cond, $pairs, $values = NULL) { $sql = []; foreach ($pairs as $name => $attr) { $sql[] = $name."=".mgDBGetSQLParam($dbh, $attr, $values !== NULL ? $values[$name] : $name); } return "UPDATE ".$table." SET ".implode(",", $sql). ($cond != "" ? " ".$cond : ""); } function mgDBPrepareSQL_V($dbh, $fmt, $argv) { $len = strlen($fmt); $sql = ""; $argn = 0; $argc = count($argv); for ($pos = 0; $pos < $len; $pos++) { if ($fmt[$pos] == "%") { if ($argn < $argc) $sql .= mgDBGetSQLParam($dbh, $fmt[++$pos], $argv[$argn++]); else { mgError("Invalid SQL statement format string '".$fmt. "', not enough parameters specified (".$argn." of ".$argc.")"); return FALSE; } } else $sql .= $fmt[$pos]; } return $sql; } function mgDBPrepareSQL($dbh) { $argv = func_get_args(); return mgDBPrepareSQL_V($dbh, $argv[1], array_splice($argv, 2)); } function mgPrepareSQL() { global $db; $argv = func_get_args(); return mgDBPrepareSQL_V($db, $argv[0], array_splice($argv, 1)); } function mgDBExecSQLInsert($dbh, $sql) { switch ($dbh->getAttribute(PDO::ATTR_DRIVER_NAME)) { case "pgsql": if (($res = mgDBFetchSQLColumn($dbh, $sql." RETURNING id")) !== false) return $res; else return FALSE; default: if (mgDBExecSQL($dbh, $sql) !== false) return $dbh->lastInsertId(); else return FALSE; } } function mgDBExecSQL($dbh, $sql) { if (($res = $dbh->query($sql)) !== FALSE) return $res; else { mgLogSQLError($dbh, $sql); return FALSE; } } function mgDBFetchSQL($dbh, $sql) { if (($res = $dbh->query($sql)) !== FALSE) return $res->fetch(); else { mgLogSQLError($dbh, $sql); return FALSE; } } function mgDBFetchSQLColumn($dbh, $sql, $column = 0) { if (($res = $dbh->query($sql)) !== FALSE) return $res->fetchColumn($column); else { mgLogSQLError($dbh, $sql); return FALSE; } } function mgPrepareSQLUpdate($table, $cond, $pairs) { global $db; return mgDBPrepareSQLUpdate($db, $table, $cond, $pairs); } function mgExecSQLInsert($sql) { global $db; return mgDBExecSQLInsert($db, $sql); } function mgExecSQL($sql) { global $db; return mgDBExecSQL($db, $sql); } function mgFetchSQL($sql) { global $db; return mgDBFetchSQL($db, $sql); } function mgFetchSQLColumn($sql, $column = 0) { global $db; return mgDBFetchSQLColumn($db, $sql, $column); } function mgDBBeginTransaction($dbh = FALSE) { global $db; return mgDBExecSQL(($dbh !== FALSE) ? $dbh : $db, "BEGIN TRANSACTION"); } function mgDBCommitTransaction($dbh = FALSE) { global $db; return mgDBExecSQL(($dbh !== FALSE) ? $dbh : $db, "COMMIT"); } function mgDBGetTableSchema($dbh, $schema) { $res = []; $driver = $dbh->getAttribute(PDO::ATTR_DRIVER_NAME); // Go through the table schema, definition by definition foreach ($schema as $scol) { $tmp = []; // And each element of the one definition // (like 'foo INTEGER AUTOINCREMENT') foreach ($scol as $elem) switch ($driver) { case "pgsql": switch ($elem) { case "AUTOINCREMENT": // For Postgres, use SERIAL for autoincrement and // "cleverly" replace the 2nd element with SERIAL // assuming that it is INTEGER or such. $tmp[1] = "SERIAL"; break; case "DATETIME": $tmp[] = "TIMESTAMPTZ"; break; default: $tmp[] = $elem; break; } break; case "mysql": switch ($elem) { case "AUTOINCREMENT": $tmp[] = "AUTO_INCREMENT"; break; case "DATETIME": $tmp[] = "TIMESTAMP"; break; default: $tmp[] = $elem; break; } break; case "sqlite": $tmp[] = $elem; break; default: die("Don't know how to handle PDO driver '".$driver."' yet.\n"); } $res[] = implode(" ", $tmp); } return implode(", ", $res); } function mgDBCreateOneTable($dbh, $name, $schema) { return (mgDBExecSQL($dbh, "CREATE TABLE IF NOT EXISTS ".$name." (".$schema.")") !== FALSE) ? TRUE : FALSE; } ?>