view index.php @ 150:5c0eacb7d35d

Use the renamed framework include.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 20 Sep 2014 07:39:10 +0300
parents 834abfd9d8e9
children 9c6290ad087d
line wrap: on
line source

<?php
//
// OAMK Lukkari v2.3
// (C) Copyright 2010 - 2014 Matti 'ccr' Hämäläinen <ccr@tnsp.org>
// Yes, this code is rather horrible. :|
//
// Include framework
require "msitegen.inc.php";

// Default settings
$pageName = "OAMK Lukkari";
$pageVersion = "2.3";
$mobileMode = FALSE;
$baseURI = "http://example.com/";

$pageLanguages = array("fi", "en");
$pageCSSData = array("cookie" => "lukcss", "prefix" => "luk");

$classDefaultID = "DEFAULT";
$classIDFile = "classes.txt";
$courseCacheFile = "coursecache.txt";

if (file_exists("config.inc.php"))
  @require "config.inc.php";

//
// Hardcoded tables
//
$lukDayNames = array(
  "fi" => array("Maanantai", "Tiistai", "Keskiviikko", "Torstai", "Perjantai", "Lauantai", "Sunnuntai"),
  "en" => array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"),
);

$pageTranslations = array(
  "Original" => array("fi" => "Alkuperäinen"),

  "Shown" => array("fi" => "Näkyvillä"),
  "Next period" => array("fi" => "Seuraava periodi"),
  "Current period" => array("fi" => "Nykyinen periodi"),
  "Switch" => array("fi" => "Vaihda"),

  "contact" => array(
    "en" => "Contact <b>%1</b> or <b>%2</b>. ".
    "The author can't be held responsible for any errors or inaccuracies in the data!",

    "fi" => "Yhteydenotot <b>%1</b> tai <b>%2</b>. ".
    "En vastaa mahdollisista virheistä tai epätarkkuuksista tiedoissa!",
  ),
  
  "updated" => array(
    "en" => "Last updated: <b>%1</b>.",
    "fi" => "Päivitetty: <b>%1</b>.",
  ),
  
  "beta" => array(
    "en" => " NOTICE! %2 v%1 is still under development. There may be bugs.",
    "fi" => " HUOM! %2 v%1 on vielä kehityksen alla. Bugeja voi löytyä.",
  ),

  "viikossa" => array(
    "en" => "Total of <b>%1</b> hours in the week.",
    "fi" => "Viikossa yhteensä <b>%1</b> tuntia.",
  ),

  "vuoroviikoin" => array(
    "en" => "Every other week",
    "fi" => "Vuoroviikoin",
  ),

  "classNotSet" => array(
    "en" => "Class not set, using default <b>%1</b>.",
    "fi" => "Luokkaa ei asetettu, käytetään vakioarvoa <b>%1</b>.",
  ),

  "classDataNotFound" => array(
    "fi" => "Luokan %1 tietoja ei löytynyt! Jos luokkakoodi on uusi, ".
    "ilmestyy se järjestelmään seuraavan päivityksen aikana. Luokkatiedot ".
    "päivitetään noin kerran viikossa.",

    "en" => "Data for class %1 was not found. If the class code is new, it ".
    "should appear in this system during the next update. The data is updated ".
    "approximately once per week.",
  ),
  
  "classListNotFound" => array(
    "fi" => "Luokkien listaa ei löytynyt. Kokeile ladata sivu uudelleen hetken kuluttua.",
    "en" => "Class list not found. An update may be in progress, try reloading in a minute.",
  ),
  
  "classFormatError" => array(
    "fi" => "Virhe! Luokan täytyy olla muotoa <b>XXXnXXX</b>, käytetään vakioarvoa <b>%1</b>.",
    "en" => "Error! Class code must be of format <b>XXXnXXX</b>, using default value of <b>%1</b>.",
  ),

  "Style" => array(
    "fi" => "Tyyli",
  ),
  
  "currLukLink" => array(
    "fi" => "Linkki tähän lukujärjestykseen nykyisillä asetuksilla (kieli, jne.)",
    "en" => "Link to the this timetable with current settings (language, etc.)",
  ),
//  "" => array("fi" => ),
);


function lukGetDayName($day)
{
  global $lukDayNames, $pageLang;

  if (isset($lukDayNames[$pageLang]) && isset($lukDayNames[$pageLang][$day]))
    return $lukDayNames[$pageLang][$day];
  else
    return $lukDayNames["en"][$day];
}


function lukCheckClassID(&$id)
{
  global $classDefaultID;
  if (preg_match("#^([A-Z]{3}\d[A-Za-z0-9_]{1,6}|ccr|Ryh_[A-Z]{3}\d[A-Za-z0-9_]{1,6})$#", $id, $m))
  {
    $id = $m[1];
    return TRUE;
  } else {
    stError(cmQM("classFormatError", $classDefaultID));
    $id = $classDefaultID;
    return FALSE;
  }
}


function lukGetWeekdayFromTimestamp($stamp)
{
  $info = getdate($stamp);
  $day = $info["wday"];
  return ($day > 0) ? $day - 1 : $day + 6;
}


function lukGetHourStamp($stamp)
{
  return date("H:i", mktime(0, 0, $stamp, 0, 0, 0));
}


function lukGetHourStr($hour)
{
  global $classHourTimes;
  if (isset($classHourTimes[$hour]))
  {
    return
      "<br />".
      lukGetHourStamp($classHourTimes[$hour]["start"]).
      " - ".
      lukGetHourStamp($classHourTimes[$hour]["end"]).
      "<br /><br />";
  }
  else
    return "ERROR";
}


function lukClassGetHourStr($start, $end)
{
  global $classHourTimes;
  return
    lukGetHourStamp($classHourTimes[$start]["start"]).
    " - ".
    lukGetHourStamp($classHourTimes[$end]["end"]);
}


function lukMatchCourse($id)
{
  global $cache, $cacheDirty, $pageCharset, $pageLang, $mobileMode;

  //$uri = "http://www.oamk.fi/opiskelijalle/rakenne/opinto-opas/koulutusohjelmat/?sivu=oj&kieli=".strtoupper($pageLang)."&koodi1=".$id;
  $uri = "http://www.oamk.fi/koulutus_ja_hakeminen/opiskelu_oamkissa/opinto-opas/koulutusohjelmat/?sivu=oj_kuvaus&koodi1=".$id."&kieli=".strtoupper($pageLang);

  // Create the index
  if (!isset($cache[$id]))
    $cache[$id] = array();

  // Check if course exists in cache
  if (!isset($cache[$id][$pageLang]))
  {
    // Not cached, try to fetch data
    $cacheDirty = TRUE;
    $data = @file_get_contents($uri);
    if ($data !== FALSE)
    {
      $data = @iconv("iso-8859-15", $pageCharset, $data);
      if (preg_match("#<td class=\"smallheadercell\"><strong>(.+?)\s+(\d+)\s*(op|ECTS\s+cr)\s*</strong></td>#", $data, $m))
      {
        // Add data to cache
        $cache[$id][$pageLang] = array("desc" => $m[1], "op" => intval($m[2]));
      }
    }
  }
  
  if (isset($cache[$id]) && isset($cache[$id][$pageLang]))
  {
    if ($mobileMode)
    {
      return "<b>".chentities($cache[$id][$pageLang]["desc"])."</b>";
    }
    else
    {
       return
         "<a target=\"_blank\" title=\"".chentities($id." - ".$cache[$id][$pageLang]["op"]." op").
         "\" href=\"".chentities($uri)."\">".chentities($cache[$id][$pageLang]["desc"])."</a>";
    }
  }
  else
    return chentities($id);
}


function lukGetClassInfo($class)
{
  $data = $class["data"];
  if ($class["grouped"])
  {
    $out = "<table><tr>";

    $maxCount = 0;
    foreach ($data as $col)
    {
      $out .= "<td>".lukMatchCourse($col[0])."</td>";
      if (count($col) > $maxCount)
        $maxCount = count($col);
    }
    $out .= "</tr>";

    for ($i = 1; $i < $maxCount; $i++)
    {
      $out .= "<tr>";
      foreach ($data as $col)
      {
        $out .= "<td>";
        if (isset($col[$i]))
          $out .= chentities($col[$i]);
        $out .= "</td>";
      }
      $out .= "</tr>";
    }

    $out .= "</table>";
    
    if ($class["turns"])
      $out .= cmQM("vuoroviikoin");

    return $out;
  }
  else
  {
    $out = lukMatchCourse($data[0][0])."<br />";

    for ($i = 1; $i < count($data[0]); $i++)
    {
      $out .= chentities($data[0][$i])."<br />";
    }
    if ($class["turns"])
      $out .= cmQM("vuoroviikoin");

    return $out;
  }
}


function lukFindClass($day, $hour)
{
  global $classHourDefs, $classDayTable;
  if (isset($classDayTable[$day]))
  {
    foreach ($classDayTable[$day] as $id)
    {
      if ($hour >= $classHourDefs[$id]["start"] && 
          $hour <  $classHourDefs[$id]["start"] + $classHourDefs[$id]["hours"])
        return $id;
    }
  }
  return 0;
}


function lukReadClassFile($filename, &$mtimestamp)
{
  // Attempt to open file for reading
  if (($fp = @fopen($filename, "rb")) === false)
    return false;

  $mtimestamp = filemtime($filename);
  $mclasses = FALSE;

  // Lock file so that we do not get clashes
  if (flock($fp, LOCK_SH))
  {
    $mclasses = array();
    // Read and parse data
    while (!feof($fp))
    {
      $str = trim(fgets($fp, 128));
      if (strlen($str) > 2 && $str[0] != "#")
        $mclasses[] = $str;
    }

    // Release lock
    flock($fp, LOCK_UN);
  }

  fclose($fp);
  return $mclasses;
}


function lukPrintTimeTable($mini)
{
  global $classInfo, $classHourDefs, $classHourTimes;
  
//  $currStamp = time() + ((3 * 60) + 45) * 60;
  $currStamp = time();
  $currTime = $currStamp - mktime(0, 0, 0);
  $currDay = lukGetWeekdayFromTimestamp($currStamp);

  $nextStamp = $currStamp + 30 * 60;
  $nextTime = $nextStamp - mktime(0, 0, 0);
  
  // Create the timetable table
  if ($mini)
  {
    $out =
    "<table id=\"timeTable\">\n".
    " <tr>\n".
    "  <th></th>".
    "  <th class=\"days\">".lukGetDayName($currDay)."</th>\n".
    " </tr>\n";

    $startDay = $currDay;
    $lastDay = $currDay + 1;
  }
  else
  {
    $out =
    "<p>".join("; ", $classInfo["general"]).
    //" [".cmQM("viikossa", $classInfo["totalHours"])."]".
    "</p>\n".
    "<table id=\"timeTable\">\n".
    " <tr>\n".
    "  <th></th>\n";
    
    $cellWidth = $classInfo["maxDays"] > 0 ? 100 / $classInfo["maxDays"] : 15;
    if ($cellWidth > 25) $cellWidth = 25;

    for ($day = 0; $day < $classInfo["maxDays"]; $day++)
    {
      $out .=  "  <th style=\"width: ".$cellWidth."%;\" class=\"days\">".lukGetDayName($day)."</th>\n";
    }
    $out .= " </tr>\n";
    $startDay = 0;
    $lastDay = $classInfo["maxDays"];
  }


  for ($hour = $classInfo["firstHour"]; $hour < $classInfo["lastHour"]; $hour++)
  {
    $out .= " <tr>\n".
    "  <th class=\"hours\">".lukGetHourStr($hour)."</th>\n";
    for ($day = $startDay; $day < $lastDay; $day++)
    {
      $id = lukFindClass($day, $hour);
      if ($id > 0)
      {
        $class = &$classHourDefs[$id];
        if (!isset($class["set"]))
        {
          $class["set"] = TRUE;

          $nextActive = $day == $currDay && 
                      $nextTime >= $classHourTimes[$class["start"]]["start"] &&
                      $nextTime <  $classHourTimes[$class["start"] + $class["hours"] - 1]["end"];

          $isActive = $day == $currDay && 
                      $currTime >= $classHourTimes[$class["start"]]["start"] &&
                      $currTime <  $classHourTimes[$class["start"] + $class["hours"] - 1]["end"];

          $out .= "  <td rowspan=\"".$class["hours"]."\" ".
          "title=\"".lukClassGetHourStr($hour, $hour + $class["hours"] - 1)."\" class=\"".
          ($isActive ? "clactive " : "").
          (!$isActive && $nextActive ? "clnext " : "").
          (($class["grouped"] || $class["turns"]) ? "clgrouped" : "clnormal")."\">".
          lukGetClassInfo($class).
          "<div class=\"nhours\"><span>".$class["hours"]."h</span></div></td>\n";
        }
      }
      else
      {
        $out .= "  <td class=\"clnothing\"></td>\n";
      }
    }
    $out .= " </tr>\n";
  }

  return $out."</table>\n";
}



//
// Main code begins
//
// Check given parameters:
// Language must be the first setting to be validated,
// so that the translation support works properly.
//

if (($tmp = stGetRequestItem("lang", FALSE, TRUE)) !== FALSE)
{
  $tmp = strtolower($tmp);
  if (in_array($tmp, $pageLanguages))
  {
    $pageLang = $tmp;
    setcookie("luklang", $tmp, time() + 365*24*60*60); // expire in a year
  }
}
else
if (isset($_COOKIE["luklang"]))
{
  $tmp = $_COOKIE["luklang"];
  if (in_array($tmp, $pageLanguages))
    $pageLang = $tmp;
}


// Check class setting
if (($classID = stGetRequestItem("luokka", FALSE, TRUE)) !== FALSE && lukCheckClassID($classID))
{
  setcookie("lukluokka", $classID, time() + 365*24*60*60); // expire in a year
}
else
if (isset($_COOKIE["lukluokka"]))
{
  $classID = $_COOKIE["lukluokka"];
  lukCheckClassID($classID);
}
else
{
  stError(cmQM("classNotSet", $classDefaultID));
  $classID = $classDefaultID;
}


// Check next period flag
if (isset($_REQUEST["next"]))
{
  $nextPeriod = TRUE;
  $cachePath = "cache-next/";
}
else
{
  $nextPeriod = FALSE;
  $cachePath = "cache/";
}

if (file_exists($cachePath."baseuri.data"))
{
  require $cachePath."baseuri.data";
}


// Global cache for course data
$cache = array();
$cacheDirty = FALSE;

// Try to read cachefile, if we can get file lock on it
$fp = @fopen($courseCacheFile, "rb");
if ($fp)
{
  if (flock($fp, LOCK_SH))
  {
    require($courseCacheFile);
    flock($fp, LOCK_UN);
  }
  fclose($fp);
}


// Read classfile
if (($classIDs = lukReadClassFile($classIDFile, &$timestamp)) === false)
  stError(cmQM("classListNotFound"));


// Read class data
$dataFile = $cachePath.$classID.".data";
if (!file_exists($dataFile))
{
  stError(cmQM("classDataNotFound", chentities($classID)));
  $haveData = FALSE;
}
else
{
  require($dataFile);
  $haveData = isset($classInfo);
}


// Create references to mobile device (Apple touch) icons
$extra = "";
foreach (array(57 => FALSE, 76 => TRUE, 114 => TRUE, 120 => TRUE, 152 => TRUE) as $iconSize => $addSize)
{
  $extra .= "  <link rel=\"apple-touch-icon\" ".
    ($addSize ? "sizes=\"".$iconSize."x".$iconSize."\" " : "").
    "href=\"img/icon-".$iconSize."-precomposed.png\" />\n";
}


// Start printing the page
$pageTitle = $haveData ? $classID." / ".join("; ", $classInfo["info"]) : $classID;
cmPrintPageHeader($pageTitle." - ".$pageName, $extra);


// Info box
echo
  "<div id=\"infobox\">\n".
  " <div id=\"ctitle\">".$pageName." v".$pageVersion."</div>\n";

if (!$mobileMode)
{
  echo
    " <div id=\"csssel\">".cmQM("Style").": ";

  if (isset($pageCSSAlts))
  {
    foreach ($pageCSSAlts as $name => $id)
    {
      echo
        "<a ".(($pageCSSIndex == $id) ? "class=\"selected\" " : "").
        "href=\"".$baseURI."?css=".$id."\">".$name."</a>";
    }
  }

  echo
    "</div>\n";
}

echo
  " <div id=\"clang\">";

foreach ($pageLanguages as $id)
{
  echo
    "<a ".(($pageLang == $id) ? "class=\"selected\" " : "").
    "href=\"".$baseURI."?lang=".$id."\">".$id."</a>";
}

echo
  "</div>\n".
  "</div>\n";


// Additional controls
echo
  "<form id=\"controls\" action=\"".$baseURI."\" method=\"get\">\n".
  " <table>\n".
  "  <tr>\n".
  "   <th>\n".
  "    <select name=\"luokka\">\n";

if ($classIDs !== FALSE)
{
  foreach ($classIDs as $id)
  {
    echo
      "     <option ".($classID == $id ? "selected=\"selected\" " : "").
      "value=\"".$id."\">".chentities($id)."</option>\n";
  }
}

echo 
  "    </select>\n".
  "   </th>\n".
  "   <th><input class=\"submit\" type=\"submit\" value=\"".cmQM("Switch")."\" /></th>\n";

if (!$mobileMode)
{
  echo
    "   <th><a id=\"next\" class=\"textctrl\" href=\"".$baseURI.($nextPeriod ? "" : "?next")."\">".
    cmQM("Shown").": ".($nextPeriod ? cmQM("Next period") : cmQM("Current period")).
    "</a></th>\n";
  
  if ($haveData)
  {
    echo
    "   <th><a id=\"orig\" class=\"textctrl\" href=\"".$origBaseURI.$classID.$origBaseExt."\">".cmQM("Original")."</a></th>\n";
    //"   <th><a id=\"xml\" class=\"textctrl\" href=\"".$baseURI.$cachePath."/".$luokka.".xml\">XML</a></th>\n";
  }
  
  echo
    "   <th><a class=\"textctrl mobile\" href=\"http://tnsp.org/mluk/\">Mobile</a></th>\n";
}

$currURL = $baseURI."?luokka=".$classID."&amp;lang=".$pageLang.
  (isset($pageCSSIndex) ? "&amp;css=".$pageCSSIndex : "").
  ($nextPeriod ? "&amp;next" : "");

echo
  "   <th><a href=\"".$currURL."\" class=\"textctrl\" title=\"".cmQM("currLukLink")."\">Link</a></th>\n".
//  "   <th class=\"advert\"><a href=\"http://tnsp.org/u/HXh\"><img src=\"img/cell.png\" alt=\"Division Cell\" /></a></th>\n".
  "   <th class=\"advert\"><a href=\"http://tnsp.org/u/G1X\"><img src=\"img/hdd_fi.gif\" alt=\"HDD.fi\" /></a></th>\n".
  "  </tr>\n".
  " </table>\n".
  "</form>\n".
  "<h1>".$pageTitle."</h1>\n";

// Show error messages
if ($errorSet)
{
  echo "<ul>\n";
  foreach ($errorMsgs as $msg)
    echo "<li>".$msg."</li>\n";
  echo "</ul>\n";
}

if ($haveData)
{
  echo lukPrintTimeTable($mobileMode);
}

echo
  "<div id=\"footer\">".
  cmQM("contact", "ccr @ IRCNet", "ccr (at) tnsp (dot) org").
  " / ".
  cmQM("updated", strftime("%d.%m.%Y, %H:%M", $timestamp)).
  //" <div style=\"color: red;\">".cmQM("beta", $pageVersion, $pageName)."</div>\n".
  "</div>\n";

cmPrintPageFooter();


// Dump the course data cache, but only if it has changed
if ($cacheDirty)
{
  $str = "<?\n\$cache = ".var_export($cache, TRUE)."\n?>";
  if (file_put_contents($courseCacheFile, $str, LOCK_EX) === FALSE)
  {
    // Can't do much anything here ..
  }
}

?>