view mgallery.inc.php @ 348:596196f2b0c5 default tip

Improve relative URL translation in header text blobs.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 20 Dec 2023 09:17:55 +0200
parents 7da360685721
children
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-2023 Tecnic Software productions (TNSP)
//

$mgProgVersion = "v0.9.14";
$mgProgInfo = "Programmed by Matti 'ccr' Hamalainen";
$mgProgEmail = "<ccr@tnsp.org>";
$mgProgCopyright = "2015-2023 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("MG_CALLABLE"         , 9);

$mgValueTypes = [
  MG_STR                   => "string",
  MG_STR_LC                => "string lc",
  MG_STR_ARRAY             => "string array",
  MG_INT                   => "int",
  MG_DVA                   => "dva",
  MG_BOOL                  => "bool",
  MG_FLAGS                 => "flags",
  MG_DATE                  => "date",
  MG_CALLABLE              => "callable",
];


$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],
  "show_keywords"    => [MG_CALLABLE, FALSE, "mgParseShowKeywords"],

  "title_prefix"     => [MG_STR, ""],
  "title_sep"        => [MG_STR, " - "],
  "page_info"        => [MG_STR, "Powered by <b>MGallery ".$mgProgVersion."</b> &copy; 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],
];


//
// Gallery album settings
//
$mgAlbumDefaults = [
  "show_keywords"    => [MG_CALLABLE, FALSE, "mgParseShowKeywords"],
  "hide"             => [MG_BOOL, FALSE],
  "hide_contents"    => [MG_BOOL, FALSE],
  "albumpic"         => [MG_STR, FALSE],
  "tn_format"        => [MG_STR_LC, "jpeg"],
  "med_format"       => [MG_STR_LC, "jpeg"],

  "header"           => [MG_STR_ARRAY, FALSE],
  "caption"          => [MG_STR_ARRAY, FALSE],
  "title"            => [MG_STR_ARRAY, FALSE],
];


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");
  }

  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 mgParseShowKeywords($val)
{
  return preg_split("/\s*[,|]\s*/", $val, -1, PREG_SPLIT_NO_EMPTY);
}


function mgInvalidType(&$defaults, $key, $val)
{
  global $mgValueTypes;

  mgFatal("Invalid value type '".gettype($val)."' for setting '".$key."', expected '".
    $mgValueTypes[$defaults[$key][0]]."', value: '".$val."'.\n");

  return FALSE;
}


function mgParseConfigSetting(&$settings, &$defaults, $key, $val)
{
  if (!array_key_exists($key, $defaults))
    return mgFatal("Unknown setting key '".$key."'.\n");

  switch ($defaults[$key][0])
  {
    case MG_STR:
      if (!is_string($val))
        return mgInvalidType($defaults, $key, $val);
      break;

    case MG_STR_LC:
      if (!is_string($val))
        return mgInvalidType($defaults, $key, $val);

      $val = strtolower($val);
      break;

    case MG_STR_ARRAY:
      if (is_string($val))
        $val = array($val);

      if (!is_array($val))
        return mgInvalidType($defaults, $key, $val);
      break;

    case MG_INT:
      if (!is_int($val))
        return mgInvalidType($defaults, $key, $val);
      break;

    case MG_BOOL:
      if (is_string($val))
      {
        switch (strtolower(trim($val)))
        {
          case "yes": case "on": case "true": case "1":
            $val = true;
            break;

          case "no": case "off": case "false": case "0":
            $val = false;
            break;

          default:
            mgInvalidType($defaults, $key, $val);
        }
      }

      if (!is_bool($val) && !is_int($val))
        return mgInvalidType($defaults, $key, $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
            return mgFatal("Invalid flag value for '".$key."': '".$qval."'.");
        }
        $val = $nval;
      } else
        return mgInvalidType($defaults, $key, $val);
      break;

    case MG_CALLABLE:
      if (!is_callable($defaults[$key][2]))
        return mgInvalidType($defaults, $key, $val);

      $val = call_user_func($defaults[$key][2], $val);
      break;
  }

  $settings[$key] = $val;
  return TRUE;
}


function mgReadOneConfig(&$searchPaths, $pathList)
{
  global $mgSettings, $mgDefaults, $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)
          mgParseConfigSetting($mgSettings, $mgDefaults, $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;
}


?>