view index.php @ 23:ce5509f09992

Fix certain GET parameter parsing cases to decode URL encoding properly.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 03 Jun 2016 19:18:02 +0300
parents f8a77f25dad6
children 3c7d311249e3
line wrap: on
line source

<?
//
// BatMUD material information browser
// (C) Copyright 2009 - 2016 Matti 'ccr' Hämäläinen <ccr@tnsp.org>
//
require "mgeneric.inc.php";
require "materials.inc.php";

$pageTitle = "Pupunen BatMUD Material Browser";
$pageIndex = "index.php";

$infoNotes =
[
  "All material data updated as of November 2011 with some updates in 2014 and 2015.",
  "This information is free to use in any way you wish. It would be nice to be credited, however.",
  "There may be bugs. If you notice any inaccuracies, contact <b>Ggr</b> @ Bat.",
  "<b>Raw material data is also available in <a href=\"materials.csv\">CSV format</a>, <a href=\"materials_short.txt\">short tabular format</a> and <a href=\"materials_long.txt\">long format</a></b>.",
  "You can sort by any column by clicking on the column name. Clicking again will change
   sorting direction (ascending/descending).",
  "Filtering to show only certain type of materials or materials with certain feature(s) is possible,
   for example <a href=\"index.php?s=0&amp;d=asc&amp;f[1]=5&amp;f[2]=6\">show only 'incr. sturdy'
   AND 'highly magical'</a> materials. Click on desired feature (table cell) to add a filter.",
  "Columns can be disabled from the filtering list (shift or ctrl with mouse click to select several)",
  "The code for these pages and Perl + shellscript based backend utilities are available in
  <a href=\"http://pupunen.net/hg/materials/\">a Mercurial repository</a>.",
];


function stParseList($values, $pair)
{
  $res = [];
  if ($values === FALSE)
    return $res;

  // It's an array already
  if (is_array($values))
  {
    if ($pair)
    {
      // The data should already be in our desired format .. maybe
      foreach ($values as $key => $val)
        $res[trim($key)] = trim($val);
    }
    else
    {
      // Place values in hash
      foreach ($values as $key)
        $res[trim($key)] = 1;
    }
    return $res;
  }
  $values = trim(urldecode($values));

  // Assume string, parse it
  if (($list = preg_split("/\s*,\s*/", $values, -1, PREG_SPLIT_NO_EMPTY)) === FALSE)
    return $res;

  if ($pair)
  {
    // Parse key-value pairs separated by :
    foreach ($list as $str)
    {
      if (($tmp = preg_split("/\s*:\s*/", $str, -1, PREG_SPLIT_NO_EMPTY)) !== FALSE)
        $res[$tmp[0]] = $tmp[1];
    }
  }
  else
  {
    // Should be just values, so place them in hash
    foreach ($list as $str)
      $res[$str] = 1;
  }
  return $res;
}


function stMakeList($name, $url, $array, $pair)
{
  if (count($array) == 0)
    return "";

  if ($pair)
  {
    $elems = [];
    foreach ($array as $key => $val)
      $elems[] = $key.":".$val;
  }
  else
  {
    $elems = array_keys($array);
  }

  $tmp = urlencode(implode(",", $elems));
  if ($url)
    return "&amp;".$name."=".$tmp;
  else
    return stGetFormHiddenInput($name, $tmp)."\n";
}


function stGetTC($a, $column)
{
  global $setSortColumn;
  return "<".$a.($column == $setSortColumn ? " class=\"hilite\"" : "").">";
}


function stGetURLStr($cfilters, $col, $dir, $domfilters, $mfilters)
{
  global $sortDirs, $setHideColumns;
  $str  = "s=".$col."&amp;d=".$sortDirs[$dir]."&amp;mf=".$domfilters;
  $str .= stMakeList("f", TRUE, $cfilters, TRUE);
  $str .= stMakeList("h", TRUE, $setHideColumns, FALSE);
  $str .= stMakeList("m", TRUE, $mfilters, FALSE);
  return $str;
}


function stSortMatFunc($a, $b)
{
  global $setSortDirection, $setSortColumn;
  $index = $setSortColumn - 1;

  if ($a[$index] == $b[$index])
    return 0;

  $res = $a[$index] < $b[$index];

  if ($setSortDirection)
    return $res ? 1 : -1;
  else
    return $res ? -1 : 1;
}


//
// Actual code starts
//
$sortDirs = [ "asc", "desc" ];

// Horrible kludge
$agent = $_SERVER["HTTP_USER_AGENT"];
if (stristr($agent, "GoogleBot") !== FALSE)
{
  header("HTTP/1.1 403 Forbidden");
  exit;
}

// Sorting column
$setSortColumn = intval(stGetRequestItem("s", 0, TRUE));
$setSortDirection = substr(strtolower(stGetRequestItem("d", "", TRUE)), 0, 1) == "d";

// Material column hiding
$setHideColumns = stParseList(stGetRequestItem("h", FALSE, TRUE), FALSE);

// Column filters
$setAttrFilters = stParseList(stGetRequestItem("f", FALSE, TRUE), TRUE);

// Material filters
$setMatFilters = stParseList(stGetRequestItem("m", FALSE, TRUE), FALSE);
$setEnableMatFilters = intval(stGetRequestItem("mf", 0, TRUE));


// Sort materials by selected column
if ($setSortColumn <= 0 || $setSortColumn >= 18)
{
  $setSortColumn = 0;
  if ($setSortDirection)
    krsort($matDataTable, SORT_STRING);
  else
    ksort($matDataTable, SORT_STRING);
}
else
  uasort($matDataTable, "stSortMatFunc");


// Print page header
cmPrintPageHeader($pageTitle, "
 <meta name=\"robots\" content=\"nofollow\" />
 <style type=\"text/css\">
    td a.matToggle {
            display: inline-block;
            background: black;
            width: 1em;
            font-size: 1.2em;
            padding: 0.1em;
            text-align: center;
            margin-right: 0.3em;
    }

    td a.matToggle:hover {
            text-decoration: none;
            background: white;
    }

    td a.matToggle.active {
            color: green !important;
    }

    td a.matToggle.inactive {
            color: red !important;
    }
 </style>
");

echo
  "<h1>".$pageTitle."</h1>\n".
  "<form action=\"".$pageIndex."\" method=\"get\">\n".
  stGetFormHiddenInput("s", $setSortColumn)."\n".
  stGetFormHiddenInput("d", $sortDirs[$setSortDirection])."\n".
  stGetFormHiddenInput("mf", $setEnableMatFilters)."\n".
  stMakeList("f", FALSE, $setAttrFilters, TRUE).
  stMakeList("m", FALSE, $setMatFilters, FALSE).
  "<table class=\"optionsTable\">\n".
  " <tr>\n".
  "  <th>Hide columns</th>\n".
  "  <th>Show only type</th>\n".
  "  <td rowspan=\"3\" class=\"infobox\">\n".
  "   [<a href=\"".$pageIndex."\">Reset/Clear</a>] ".
  "[<a href=\"info.php\">Alloy browser</a>]\n".
  "   - <b>CHANGE COLOURS/STYLE: ";

for ($i = 1; $i <= 4; $i++)
   echo "<a href=\"?css=".$i."\">(".$i.")</a> ";

echo
   "</b>\n".
  "   <br />\n".
  "   <ul>\n".
  implode("\n", array_map(function($msg){ return "    <li>".$msg."</li>"; }, $infoNotes)).
  "   </ul>\n".
  "  </td>\n".
  " </tr>\n".
  " <tr>\n".
  "  <td>\n".
  "   <select multiple=\"multiple\" size=\"5\" name=\"h[]\">\n";

reset($matTransNames);
next($matTransNames);
while (list($key, $value) = each($matTransNames))
{
  echo "    <option".
    (isset($setHideColumns[$key]) ? " selected=\"selected\"" : "").
    " value=\"$key\">".chentities($value)."</option>\n";
}

echo
  "   </select>\n".
  "  </td>\n".
  "  <td>\n".
  "   <select name=\"f[14]\">\n";

$typeFilter = isset($setAttrFilters[14]) ? $setAttrFilters[14] : -1;
if ($typeFilter == -1) unset($setAttrFilters[14]);
$typeTable = $matTransTable[14];
$typeTable[-1] = "EVERYTHING";
ksort($typeTable);
foreach ($typeTable as $key => $value)
{
  echo
    "    <option value=\"$key\"".
    ($typeFilter == $key ? " selected=\"selected\"" : "").
    ">".chentities($value)."</option>\n";
}

echo
  "   </select>\n".
  "  </td>\n".
  " </tr>\n".
  " <tr>\n".
  "  <td colspan=\"2\" class=\"icenter\"><input type=\"submit\" value=\" Filter \" class=\"isubmit\" /></td>\n".
  " </tr>\n".
  "</table>\n".
  "</form>\n";

//
// List active filters
//
if (count($setAttrFilters) > 0)
{
  $filters = [];
  foreach ($setAttrFilters as $fkey => $fval)
  {
    if ($fkey >= 0)
      $filters[] = "<b>".strtolower($matTransNames[$fkey + 1])."</b>=".strtolower($matTransTable[$fkey][$fval]);
  }

  echo "<p class=\"attrFilters\">Filtering: ".implode(", ", $filters)."</p>\n";
}

if (count($setMatFilters) > 0)
{
  echo
    "<p class=\"materialFilters\">Material filter: ".implode(", ", array_keys($setMatFilters))." ".
    "<a href=\"?".stGetURLStr($setAttrFilters, $setSortColumn, $setSortDirection, !$setEnableMatFilters, $setMatFilters).
    "\" title=\"".($setEnableMatFilters ? "Deactivate" : "Activate")." the material filter.\">[".($setEnableMatFilters ? "Deactivate" : "Activate")."]</a></p>\n";
}


//
// Material table headers
//
echo
  "<div class=\"matTable\">\n".
  "<table class=\"matTable\">\n".
  " <tr>\n";

foreach ($matTransNames as $key => $value)
{
  if ($key == 0 || !isset($setHideColumns[$key]))
  {
    echo "  ".stGetTC("th", $key);
    if ($key < 18)
    {
      echo
      "<a href=\"?".
      stGetURLStr($setAttrFilters, $key,
      ($key == $setSortColumn) ? !$setSortDirection : $setSortDirection,
      $setEnableMatFilters, $setMatFilters).
      "\" title=\"Sort by ".chentities($value)."\">".chentities($value)."</a>";
    }
    else
      echo chentities($value);

    echo "</th>\n";
  }
}
echo " </tr>\n";


//
// Material data rows
//
foreach ($matDataTable as $mname => $mdata)
{
  //
  // Check what filters apply here
  //
  $doShow = TRUE;
  foreach ($setAttrFilters as $fkey => $fval)
  if ($fval >= 0 && $mdata[$fkey] != $fval)
  {
    $doShow = FALSE;
    break;
  }

  if ($setEnableMatFilters && !isset($setMatFilters[$mname]))
    $doShow = FALSE;

  if ($doShow)
  {
    // Create temporary filter list for material filter link
    $tmpFilters = $setMatFilters;
    if (isset($tmpFilters[$mname]))
      unset($tmpFilters[$mname]);
    else
      $tmpFilters[$mname] = 1;

    // First column is material name
    $col = 0;
    $isFiltered = isset($setMatFilters[$mname]);
    echo
      " <tr>".stGetTC("td", $col++).
      "<a class=\"matToggle ".(isset($setMatFilters[$mname]) ? "active" : "inactive").
      "\" href=\"?".stGetURLStr($setAttrFilters, $setSortColumn, $setSortDirection, $setEnableMatFilters, $tmpFilters).
      "\" title=\"".($isFiltered ? "Remove" : "Add")." '".chentities($mname)."' ".($isFiltered ? "from" : "to")." filtered materials.\">".($isFiltered ? "-" : "+")."</a>".
      "<a href=\"/mat/".urlencode($mname)."\">".chentities($mname)."</a>".
      "</td>";

    foreach ($mdata as $kkey => $kvalue)
    {
      if (!isset($setHideColumns[$kkey + 1]))
      {
        echo stGetTC("td", $col);
        if (is_array($kvalue))
        {
          // Arrays need special handling, and is bit messy
          reset($kvalue);

          if (list($nam, $lode) = each($kvalue))
            echo chentities($matTransTable[$kkey][$lode]);

          while (list($nam, $lode) = each($kvalue))
            echo ", ".chentities($matTransTable[$kkey][$lode]);
        }
        else
        {
          // Create temporary filter list for attribute filter link
          $tmpFilters = $setAttrFilters;
          if (isset($tmpFilters[$kkey]))
            unset($tmpFilters[$kkey]);
          else
            $tmpFilters[$kkey] = $kvalue;

          echo "<a href=\"?".
            stGetURLStr($tmpFilters, $setSortColumn, $setSortDirection, $setEnableMatFilters, $setMatFilters).
            "\">".chentities($matTransTable[$kkey][$kvalue])."</a>";
        }
        echo "</td>";
      }
      $col++;
    }
    echo "</tr>\n";
  }
}
echo
  "</table>\n".
  "</div>\n";

cmPrintPageFooter();
?>