add missing web components
authorPhilipp Wagner <mail@philipp-wagner.com>
Tue Oct 20 23:47:28 2009 +0200 (2009-10-20)
changeset 12d359de617352
parent 11 74033afa5604
child 13 65a3111c61fc
add missing web components
web/cafeteriamenu-xml.php
web/index.php
web/mensafood.php
web/mensen.inc.php
web/menu-rss.php
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/web/cafeteriamenu-xml.php	Tue Oct 20 23:47:28 2009 +0200
     1.3 @@ -0,0 +1,103 @@
     1.4 +<?php
     1.5 +/*
     1.6 + * Mensaplan XML output for communication with the Mensaplan plasmoid
     1.7 + * Copyright 2008  Philipp Wagner <mail@philipp-wagner.com>
     1.8 + *
     1.9 + * This program is free software: you can redistribute it and/or modify
    1.10 + * it under the terms of the GNU General Public License as published by
    1.11 + * the Free Software Foundation, either version 3 of the License, or
    1.12 + * (at your option) any later version.
    1.13 + *
    1.14 + * This program is distributed in the hope that it will be useful,
    1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 + * GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License
    1.20 + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    1.21 + */
    1.22 +require_once 'mensafood.php';
    1.23 +
    1.24 +// make sure that we get the right output formatting for floats
    1.25 +setlocale(LC_ALL, 'C');
    1.26 +
    1.27 +$categoryNames = array(
    1.28 +    MensaFood::CATEGORY_NORMAL => 'Tagesgericht',
    1.29 +    MensaFood::CATEGORY_ORGANIC => 'Biogericht',
    1.30 +    MensaFood::CATEGORY_SPECIAL => 'Aktionsessen');
    1.31 +
    1.32 +// get input parameters: action
    1.33 +if (empty($_REQUEST['action']) ||
    1.34 +    !in_array($_REQUEST['action'], array('get_locations', 'get_menu'))) {
    1.35 +    $action = 'get_menu';
    1.36 +} else {
    1.37 +    $action = $_REQUEST['action'];
    1.38 +}
    1.39 +
    1.40 +$xml = '<?xml version="1.0" encoding="utf-8"?>
    1.41 +    <cafeteriamenu version="1.0">';
    1.42 +
    1.43 +if ($action === 'get_menu') {
    1.44 +    $mensafood = new MensaFood();
    1.45 +
    1.46 +    // get input parameters: date
    1.47 +    if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $_REQUEST['date'])) {
    1.48 +        $date = new DateTime($_REQUEST['date']);
    1.49 +    } else {
    1.50 +        $date = new DateTime();
    1.51 +    }
    1.52 +    // get input parameters: location
    1.53 +    if (empty($_REQUEST['location']) || !ctype_digit($_REQUEST['location'])) {
    1.54 +        die('location request parameter missing or not a number');
    1.55 +    } else {
    1.56 +        $mensafood->setLocation($_REQUEST['location']) || die('Invalid location ID');
    1.57 +    }
    1.58 +
    1.59 +    $mensafood->setDate($date);
    1.60 +
    1.61 +    $xml .= '<menu>
    1.62 +      <location>'.$mensafood->getLocationName().'</location>
    1.63 +      <date>'.$date->format('Y-m-d').'</date>';
    1.64 +
    1.65 +    if ($mensafood->fetchFood() === false) {
    1.66 +        $xml .= '<status>closed</status>';
    1.67 +    } else {
    1.68 +        $xml .= '<status>ok</status>';
    1.69 +        $prices = $mensafood->getPrices();
    1.70 +        $dishes = $mensafood->getFood();
    1.71 +        // dishes
    1.72 +        foreach ($dishes as $foodItem) {
    1.73 +            $xml .= '<item>';
    1.74 +            $xml .= '<name>'.$categoryNames[$foodItem['category']].' '.$foodItem['categoryNumber'].'</name>';
    1.75 +            $xml .= '<value>'.$foodItem['name'].'</value>';
    1.76 +            $xml .= '<price>'.$prices[$foodItem['category']][$foodItem['categoryNumber']].'</price>';
    1.77 +            $xml .= "</item>\n";
    1.78 +        }
    1.79 +
    1.80 +        // sides
    1.81 +        $xml .= '<item>';
    1.82 +        $xml .= '<name>Beilagen</name>';
    1.83 +        $xml .= '<value>'.implode(', ', $mensafood->getSides()).'</value>';
    1.84 +        $xml .= '<price></price>';
    1.85 +        $xml .= "</item>\n";
    1.86 +    }
    1.87 +
    1.88 +    $xml .= '</menu>';
    1.89 +} elseif ($action == 'get_locations') {
    1.90 +    $mensafood = new MensaFood();
    1.91 +    $xml .= '<locations>';
    1.92 +    foreach ($mensafood->getAllLocations() as $location) {
    1.93 +        $xml .= '<location>';
    1.94 +        $xml .= '<name>'.$location['name'].'</name>';
    1.95 +        $xml .= '<address>'.$location['address'].'</address>';
    1.96 +        $xml .= '<id>'.$location['id'].'</id>';
    1.97 +        $xml .= '</location>';
    1.98 +    }
    1.99 +    $xml .= '</locations>';
   1.100 +}
   1.101 +
   1.102 +$xml .= '</cafeteriamenu>';
   1.103 +
   1.104 +header('Content-Type: text/xml');
   1.105 +echo $xml;
   1.106 +?>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/web/index.php	Tue Oct 20 23:47:28 2009 +0200
     2.3 @@ -0,0 +1,31 @@
     2.4 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     2.5 +<html xmlns="http://www.w3.org/1999/xhtml">
     2.6 +<head>
     2.7 +  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     2.8 +  <title>Mensen des Studentenwerks München</title>  
     2.9 +</head>
    2.10 +<body>
    2.11 +<h1>RSS-Feeds</h1>
    2.12 +<p>Für alle Mensen und Cafeterias sind RSS-Feeds mit dem aktuellen Speiseplan
    2.13 +verfügbar.</p>
    2.14 +
    2.15 +<ul>
    2.16 +<?php
    2.17 +include('mensen.inc.php');
    2.18 +foreach ($mensen as $mensa):
    2.19 +?>
    2.20 +  <li>
    2.21 +    <a href="menu-rss.php?id=<?=$mensa['id']?>"><?=htmlspecialchars($mensa['name'])?></a><br/>
    2.22 +    <?=htmlspecialchars($mensa['address'])?>
    2.23 +  </li>
    2.24 +<?php
    2.25 +endforeach;
    2.26 +?>
    2.27 +</ul>
    2.28 +
    2.29 +<h1>Für alle KDE4-Benutzer: Das Mensaplan-Plasmoid</h1>
    2.30 +<p>Mehr Informationen im Blog:
    2.31 +<a href="http://philipp.wagner.name/blog/2009/10/new-version-of-the-cafeteria-plasmoid/">hier</a> und
    2.32 +<a href="http://philipp.wagner.name/blog/2008/10/whats-for-lunch/"/>hier</a></p>
    2.33 +</body>
    2.34 +</html>
    2.35 \ No newline at end of file
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/web/mensafood.php	Tue Oct 20 23:47:28 2009 +0200
     3.3 @@ -0,0 +1,312 @@
     3.4 +<?php
     3.5 +/*
     3.6 + * Copyright 2008-2009  Philipp Wagner <mail@philipp-wagner.com>
     3.7 + *
     3.8 + * This program is free software: you can redistribute it and/or modify
     3.9 + * it under the terms of the GNU General Public License as published by
    3.10 + * the Free Software Foundation, either version 3 of the License, or
    3.11 + * (at your option) any later version.
    3.12 + *
    3.13 + * This program is distributed in the hope that it will be useful,
    3.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.16 + * GNU General Public License for more details.
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License
    3.19 + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    3.20 + */
    3.21 +
    3.22 +/**
    3.23 + * Mensafood class
    3.24 + *
    3.25 + * This provides a simple method of getting the food plan from the
    3.26 + * Studentenwerk Muenchen homepage together with the prices.
    3.27 + * It parses the page by transforming it into valid XML using tidy and applying
    3.28 + * XPath expressions to get the important information out of it.
    3.29 + *
    3.30 + * It requires PHP 5 with the following extensions:
    3.31 + * - tidy (install using PECL or (on Debian/Ubuntu) apt-get install php5-tidy)
    3.32 + *
    3.33 + * @author Philipp Wagner <mail@philipp-wagner.com>
    3.34 + */
    3.35 +class MensaFood
    3.36 +{
    3.37 +    const CATEGORY_NORMAL = 1;  // Tagesgericht
    3.38 +    const CATEGORY_ORGANIC = 2; // Biogericht
    3.39 +    const CATEGORY_SPECIAL = 3; // Aktionsessen
    3.40 +
    3.41 +    private $date;
    3.42 +    private $prices = null;
    3.43 +    /**
    3.44 +     * Main courses ("Gerichte")
    3.45 +     *
    3.46 +     * @var array
    3.47 +     */
    3.48 +    private $food = null;
    3.49 +    /**
    3.50 +     * Side dishes ("Beilagen")
    3.51 +     *
    3.52 +     * @var array
    3.53 +     */
    3.54 +    private $sides = null;
    3.55 +
    3.56 +    private $locations;
    3.57 +    private $locationId;
    3.58 +
    3.59 +    /**
    3.60 +     * Default constructor
    3.61 +     *
    3.62 +     * @param DateTime for which date should we get the plan?
    3.63 +     */
    3.64 +    public function __construct($date=null)
    3.65 +    {
    3.66 +        if ($date !== null) {
    3.67 +            $this->date = $date;
    3.68 +        }
    3.69 +
    3.70 +        include 'mensen.inc.php';
    3.71 +        $this->locations = $mensen;
    3.72 +    }
    3.73 +
    3.74 +    /**
    3.75 +     * Set the date for the food plan
    3.76 +     */
    3.77 +    public function setDate(DateTime $date)
    3.78 +    {
    3.79 +        $this->date = $date;
    3.80 +    }
    3.81 +
    3.82 +    private function getDomDocument($url)
    3.83 +    {
    3.84 +        $data = @file_get_contents($url);
    3.85 +        if (!$data) {
    3.86 +            throw new Exception("Unable to fetch document with URL $url");
    3.87 +        }
    3.88 +        $page = $data;
    3.89 +
    3.90 +        $tidy = new tidy;
    3.91 +        $tidy->parseString($page, array('output-xml' => true, 'numeric-entities' => true, 'indent' => true, 'add-xml-decl' => true), 'utf8');
    3.92 +        $tidy->cleanRepair();
    3.93 +
    3.94 +        $domPage = new DomDocument();
    3.95 +        $domPage->loadXML($tidy);
    3.96 +        return $domPage;
    3.97 +    }
    3.98 +
    3.99 +    /**
   3.100 +     * Fetch all prices
   3.101 +     *
   3.102 +     * The prices are available using the $this->prices variable.
   3.103 +     */
   3.104 +    protected function fetchPrices()
   3.105 +    {
   3.106 +        $this->prices = array();
   3.107 +        $url = 'http://www.studentenwerk-muenchen.de/mensa/preise_und_speisenangebot/';
   3.108 +        $domPage = $this->getDomDocument($url);
   3.109 +        $xpath = new DOMXPath($domPage);
   3.110 +        $categories = array(self::CATEGORY_NORMAL, self::CATEGORY_ORGANIC, self::CATEGORY_SPECIAL);
   3.111 +
   3.112 +        foreach ($categories as $category) {
   3.113 +            switch ($category) {
   3.114 +            case self::CATEGORY_NORMAL:
   3.115 +        $query = "/html/body[@id='mensa']/div[@id='inhalt']/div[@id='content']/table[1]/tbody/tr[position()>=1][position()<=4]";
   3.116 +                break;
   3.117 +            case self::CATEGORY_ORGANIC:
   3.118 +            case self::CATEGORY_SPECIAL:
   3.119 +                $query = "/html/body[@id='mensa']/div[@id='inhalt']/div[@id='content']/table[1]/tbody/tr[position()>11][position()<=10]";
   3.120 +                break;
   3.121 +            }
   3.122 +            $entries = $xpath->query($query);
   3.123 +
   3.124 +            $this->prices[$category] = array();
   3.125 +            foreach ($entries as $entry) {
   3.126 +                // number
   3.127 +                $tmp = trim($xpath->query("td[1]", $entry)->item(0)->nodeValue);
   3.128 +                $nr = preg_replace('/^.+gericht\s(\d+)+.*$/sm', '\1', $tmp);
   3.129 +                // price
   3.130 +                $tmp = trim($xpath->query("td[3]", $entry)->item(0)->nodeValue);
   3.131 +                $price = (float)preg_replace('/^.*(\d+),(\d{2}) .*$/', '\1.\2', $tmp);
   3.132 +
   3.133 +                $this->prices[$category][$nr] = $price;
   3.134 +            }
   3.135 +        }
   3.136 +    }
   3.137 +
   3.138 +    /**
   3.139 +     * Get the food prices
   3.140 +     *
   3.141 +     * @return array [category][number]
   3.142 +     */
   3.143 +    public function getPrices()
   3.144 +    {
   3.145 +        if ($this->prices === null) {
   3.146 +            $this->fetchPrices();
   3.147 +        }
   3.148 +        return $this->prices;
   3.149 +    }
   3.150 +
   3.151 +    /**
   3.152 +     * Get the official URL of the Studentenwerk page for this day
   3.153 +     *
   3.154 +     * Make sure to set locationId and date first!
   3.155 +     *
   3.156 +     * @return string
   3.157 +     */
   3.158 +    public function getOfficialUrl()
   3.159 +    {
   3.160 +        if (empty($this->locationId) || empty($this->date)) {
   3.161 +           throw new Exception('You need to set locationId and date first');
   3.162 +        }
   3.163 +
   3.164 +        // speiseplan_2008-03-10_421_-de.html
   3.165 +        $datef = $this->date->format('Y-m-d');
   3.166 +        return 'http://www.studentenwerk-muenchen.de/mensa/speiseplan/speiseplan_'.$datef.'_'.$this->locationId.'_-de.html';
   3.167 +    }
   3.168 +
   3.169 +    /**
   3.170 +     * Fetch all dishes and sides from the Studentenwerk homepage
   3.171 +     *
   3.172 +     * The result is available through getFood() and getSides().
   3.173 +     *
   3.174 +     * @return bool false if there is no plan for this day or problems while fetching data
   3.175 +     */
   3.176 +    public function fetchFood()
   3.177 +    {
   3.178 +        $url = $this->getOfficialUrl();
   3.179 +        try {
   3.180 +            $domPage = $this->getDomDocument($url);
   3.181 +        } catch (Exception $e) {
   3.182 +            return false;
   3.183 +        }
   3.184 +
   3.185 +        // get relevant data from DOM document
   3.186 +        $xpath = new DOMXPath($domPage);
   3.187 +        $query = "//div[@id='mitte']/table[2]//tr[position()>1]";
   3.188 +        $entries = $xpath->query($query, $domPage);
   3.189 +        $food = array();
   3.190 +        $sides = array();
   3.191 +        $nowSides = false;
   3.192 +        foreach ($entries as $entry) {
   3.193 +            $leftCell = trim($entry->childNodes->item(1)->nodeValue);
   3.194 +            $rightCell = trim($entry->childNodes->item(3)->nodeValue);
   3.195 +
   3.196 +            if ($nowSides || (empty($leftCell) || preg_match('/^Beilagen$/', $leftCell))) {
   3.197 +                // Side dishes
   3.198 +                $nowSides = true;
   3.199 +                $sideDish = trim(
   3.200 +                    preg_replace("/\s+/", ' ',
   3.201 +                        str_replace("\n", ' ', $rightCell)
   3.202 +                    )
   3.203 +                );
   3.204 +                if (preg_match('/^Aktion$/', $leftCell)) {
   3.205 +                    $sideDish .= ' (Aktion)';
   3.206 +                }
   3.207 +                $sides[] = $sideDish;
   3.208 +            } else {
   3.209 +                // Dishes
   3.210 +                // category
   3.211 +                if (strpos($leftCell, 'Tagesgericht') === 0) {
   3.212 +                    $category = self::CATEGORY_NORMAL;
   3.213 +                } elseif (strpos($leftCell, 'Biogericht') === 0) {
   3.214 +                    $category = self::CATEGORY_ORGANIC;
   3.215 +                } elseif (strpos($leftCell, 'Aktionsessen') === 0) {
   3.216 +                    $category = self::CATEGORY_SPECIAL;
   3.217 +                } else {
   3.218 +                    throw new Exception("Unknown category $leftCell");
   3.219 +                }
   3.220 +                // number
   3.221 +                $categoryNumber = preg_replace('/^\w+(?:gericht|essen) (\d).*$/', '\1', $leftCell);
   3.222 +                // food name
   3.223 +                $foodName = trim(
   3.224 +                    preg_replace("/\s+/", ' ',
   3.225 +                        str_replace("\n", ' ', $rightCell)
   3.226 +                    )
   3.227 +                );
   3.228 +                $food[] = array(
   3.229 +                    'category' => $category,
   3.230 +                    'categoryNumber' => $categoryNumber,
   3.231 +                    'name' => $foodName
   3.232 +                );
   3.233 +            }
   3.234 +        }
   3.235 +
   3.236 +        $this->sides = $sides;
   3.237 +        $this->food = $food;
   3.238 +        return true;
   3.239 +    }
   3.240 +
   3.241 +    /**
   3.242 +     * Get all dishes
   3.243 +     *
   3.244 +     * Use fetchFood() before you use this method, otherwise you'll get
   3.245 +     * an empty array.
   3.246 +     *
   3.247 +     * @return array
   3.248 +     */
   3.249 +    public function getFood()
   3.250 +    {
   3.251 +        if ($this->food === null) {
   3.252 +            return array();
   3.253 +        }
   3.254 +        return $this->food;
   3.255 +    }
   3.256 +
   3.257 +    /**
   3.258 +     * Get all sides
   3.259 +     *
   3.260 +     * Use fetchFood() before you use this method, otherwise you'll get
   3.261 +     * an empty array.
   3.262 +     *
   3.263 +     * @return array
   3.264 +     */
   3.265 +    public function getSides()
   3.266 +    {
   3.267 +        if ($this->sides === null) {
   3.268 +            return array();
   3.269 +        }
   3.270 +        return $this->sides;
   3.271 +    }
   3.272 +
   3.273 +    public function getAllLocations()
   3.274 +    {
   3.275 +        return $this->locations;
   3.276 +    }
   3.277 +
   3.278 +    /**
   3.279 +     * Set the location for which we want to get the information
   3.280 +     *
   3.281 +     * @param int location ID
   3.282 +     * @return bool false if $locationId is invalid
   3.283 +     */
   3.284 +    public function setLocation($locationId)
   3.285 +    {
   3.286 +        $valid = false;
   3.287 +        foreach ($this->locations as $location) {
   3.288 +            if ($location['id'] == $locationId) {
   3.289 +                $valid = true;
   3.290 +                break;
   3.291 +            }
   3.292 +        }
   3.293 +        if (!$valid) {
   3.294 +            return false;
   3.295 +        }
   3.296 +        $this->locationId = (int)$locationId;
   3.297 +        return true;
   3.298 +    }
   3.299 +
   3.300 +    /**
   3.301 +     * Get the location name
   3.302 +     *
   3.303 +     * @return string|false false if the given location ID is invalid
   3.304 +     */
   3.305 +    public function getLocationName()
   3.306 +    {
   3.307 +        foreach ($this->locations as $location) {
   3.308 +            if ($location['id'] === $this->locationId) {
   3.309 +                return $location['name'];
   3.310 +            }
   3.311 +        }
   3.312 +        return false;
   3.313 +    }
   3.314 +}
   3.315 +?>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/web/mensen.inc.php	Tue Oct 20 23:47:28 2009 +0200
     4.3 @@ -0,0 +1,92 @@
     4.4 +<?php
     4.5 +// ATTENTION: this file is UTF-8!
     4.6 +
     4.7 +// alle Betriebe von http://www.studentenwerk-muenchen.de/mensa/
     4.8 +$mensen = array(
     4.9 +  array(
    4.10 +    'name' => 'Mensa Leopoldstraße',
    4.11 +    'address' => 'Leopoldstraße 13a, München',
    4.12 +    'id' => 411
    4.13 +  ),
    4.14 +  array(
    4.15 +    'name' => 'Mensaria Schillerstraße',
    4.16 +    'address' => 'Schillerstr. 47, München',
    4.17 +    'id' => 413
    4.18 +  ),
    4.19 +  array(
    4.20 +    'name' => 'Mensaria Großhadern',
    4.21 +    'address' => 'Butenandstr.13 Gebäude F, München',
    4.22 +    'id' => 414
    4.23 +  ),
    4.24 +  array(
    4.25 +    'name' => 'Mensaria Martinsried',
    4.26 +    'address' => 'Großhaderner Str. 2, Planegg-Martinsried',
    4.27 +    'id' => 415
    4.28 +  ),
    4.29 +  array(
    4.30 +    'name' => 'Mensaria Schellingstraße',
    4.31 +    'address' => 'Schellingstr. 3, München',
    4.32 +    'id' => 416
    4.33 +  ),
    4.34 +  array(
    4.35 +    'name' => 'Mensaria Goethestraße',
    4.36 +    'address' => 'Goethestr. 70, München',
    4.37 +    'id' => 418
    4.38 +  ),
    4.39 +  array(
    4.40 +    'name' => 'Mensa Arcisstraße',
    4.41 +    'address' => 'Arcisstr.17, München',
    4.42 +    'id' => 421
    4.43 +  ),
    4.44 +  array(
    4.45 +    'name' => 'Mensa Garching',
    4.46 +    'address' => 'Lichtenbergstr.2, Garching',
    4.47 +    'id' => 422
    4.48 +  ),
    4.49 +  array(
    4.50 +    'name' => 'Mensa Weihenstephan',
    4.51 +    'address' => 'Am Forum 3, Freising',
    4.52 +    'id' => 423
    4.53 +  ),
    4.54 +  array(
    4.55 +    'name' => 'Mensa Lothstraße',
    4.56 +    'address' => 'Lothstr.13 d, München',
    4.57 +    'id' => 431
    4.58 +  ),
    4.59 +  array(
    4.60 +    'name' => 'Mensa Pasing',
    4.61 +    'address' => 'Am Stadtpark 20, München',
    4.62 +    'id' => 432
    4.63 +  ),
    4.64 +  array(
    4.65 +    'name' => 'Cafeteria Olympiapark',
    4.66 +    'address' => 'Connollystr.32, München',
    4.67 +    'id' => 523
    4.68 +  ),
    4.69 +  array(
    4.70 +    'name' => 'Cafeteria Mensa Garching',
    4.71 +    'address' => 'Lichtenbergstr.2, Garching',
    4.72 +    'id' => 524
    4.73 +  ),
    4.74 +  array(
    4.75 +    'name' => 'Cafeteria Akademie',
    4.76 +    'address' => 'Altes Akademiegebäude 1, Freising',
    4.77 +    'id' => 526
    4.78 +  ),
    4.79 +  array(
    4.80 +    'name' => 'Cafeteria Boltzmannstraße',
    4.81 +    'address' => 'Boltzmannstr.15, Garching',
    4.82 +    'id' => 527
    4.83 +  ),
    4.84 +  array(
    4.85 +    'name' => 'Cafeteria Karlstraße',
    4.86 +    'address' => 'Karlstr.6, München',
    4.87 +    'id' => 532
    4.88 +  ),
    4.89 +  array(
    4.90 +    'name' => 'Cafeteria Heßstraße',
    4.91 +    'address' => 'Lothstr.64 Gebäude R, München',
    4.92 +    'id' => 533
    4.93 +  )
    4.94 +);
    4.95 +?>
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/web/menu-rss.php	Tue Oct 20 23:47:28 2009 +0200
     5.3 @@ -0,0 +1,115 @@
     5.4 +<?php
     5.5 +/*
     5.6 + * Copyright 2008-2009  Philipp Wagner <mail@philipp-wagner.com>
     5.7 + *
     5.8 + * This program is free software: you can redistribute it and/or modify
     5.9 + * it under the terms of the GNU General Public License as published by
    5.10 + * the Free Software Foundation, either version 3 of the License, or
    5.11 + * (at your option) any later version.
    5.12 + *
    5.13 + * This program is distributed in the hope that it will be useful,
    5.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.16 + * GNU General Public License for more details.
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License
    5.19 + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    5.20 + */
    5.21 + 
    5.22 +define('CACHE_DIR', dirname(__FILE__).'/cache');
    5.23 +define('DEBUG', false);
    5.24 +
    5.25 +// don't do any input validation here, it's done after the cache lookup
    5.26 +// int cast is enough for now
    5.27 +if (empty($_GET['id'])) {
    5.28 +    $id = 421; // Mensa Arcisstraße - backwards compatibility
    5.29 +} else {
    5.30 +    $id = (int)$_GET['id'];
    5.31 +}
    5.32 +
    5.33 +// we cache the results for two hours to reduce the load on the Studentenwerk
    5.34 +// homepage and improve our response time
    5.35 +$cacheFile = CACHE_DIR."/menu-$id.rss";
    5.36 +if (!DEBUG && file_exists($cacheFile) && filemtime($cacheFile) > time()-60*60*2) {
    5.37 +    echo file_get_contents($cacheFile);
    5.38 +    exit;
    5.39 +}
    5.40 +
    5.41 +require_once 'mensafood.php';
    5.42 +include 'mensen.inc.php';
    5.43 +
    5.44 +setlocale(LC_ALL, 'de_DE');
    5.45 +$categoryNames = array(
    5.46 +    MensaFood::CATEGORY_NORMAL => 'Tagesgericht',
    5.47 +    MensaFood::CATEGORY_ORGANIC => 'Biogericht',
    5.48 +    MensaFood::CATEGORY_SPECIAL => 'Aktionsessen');
    5.49 +
    5.50 +// input validation
    5.51 +$idExists = false;
    5.52 +foreach ($mensen as $mensa) {
    5.53 +    if ($mensa['id'] == $id) {
    5.54 +        $idExists = true;
    5.55 +        break;
    5.56 +    }
    5.57 +}
    5.58 +if (!$idExists) {
    5.59 +    // redirect to overview page
    5.60 +    $host  = $_SERVER['HTTP_HOST'];
    5.61 +    $uri   = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
    5.62 +    $extra = 'index.php';
    5.63 +    header("Location: http://$host$uri/$extra");
    5.64 +}
    5.65 +
    5.66 +
    5.67 +$rss = '<?xml version="1.0" encoding="utf-8"?>
    5.68 +
    5.69 +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    5.70 +
    5.71 +  <channel>
    5.72 +    <title>'.htmlspecialchars($mensa['name']).'</title>
    5.73 +    <link>http://www.philipp.wagner.name</link>
    5.74 +    <atom:link href="http://philipp.wagner.name/cafeteriamenu/menu-rss.php?id='.$id.'" rel="self" type="application/rss+xml" />
    5.75 +    <description>Speiseplan des Studentenwerks München - '.htmlspecialchars($mensa['name']).'</description>
    5.76 +    <language>de-DE</language>
    5.77 +    <copyright>Philipp Wagner, mail@philipp-wagner.com</copyright>
    5.78 +    <pubDate>'.date('r').'</pubDate>';
    5.79 +
    5.80 +$mensafood = new MensaFood(new DateTime());
    5.81 +$mensafood->setLocation($id);
    5.82 +$prices = $mensafood->getPrices();
    5.83 +
    5.84 +for ($i=0; $i<=14; $i++) {
    5.85 +    $date = new DateTime("+$i day");
    5.86 +    $mensafood->setDate($date);
    5.87 +    $res = $mensafood->fetchFood();
    5.88 +    if (!$res) {
    5.89 +        continue;
    5.90 +    }
    5.91 +
    5.92 +    // RSS header
    5.93 +    $rss .= '<item><title>'.strftime('%Y-%m-%d %A', $date->format('U')).'</title>';
    5.94 +    $rss .= '<guid isPermaLink="false">'.uniqid('mensafood').'</guid>';
    5.95 +    $rss .= '<link>'.$mensafood->getOfficialUrl().'</link>';
    5.96 +    $rss .= '<description>';
    5.97 +  
    5.98 +    $desc = '';
    5.99 +    foreach ($mensafood->getFood() as $foodItem) {
   5.100 +        $desc .= '<b>'.$categoryNames[$foodItem['category']].' '.
   5.101 +                $foodItem['categoryNumber'].'</b> '.
   5.102 +                '('.number_format($prices[$foodItem['category']][$foodItem['categoryNumber']], 2, ',', '.').' EUR): '.
   5.103 +                $foodItem['name'].'<br>';
   5.104 +    }
   5.105 +    $desc .= '<br>';
   5.106 +    $desc .= '<b>Beilagen:</b> '.implode(', ', $mensafood->getSides());
   5.107 +
   5.108 +    $rss .= htmlspecialchars($desc);
   5.109 +    $rss .= '</description></item>';
   5.110 +}
   5.111 +
   5.112 +$mensafood->fetchFood();
   5.113 +$rss .= '</channel></rss>';
   5.114 +file_put_contents($cacheFile, $rss);
   5.115 +
   5.116 +header('Content-Type: application/rss+xml');
   5.117 +echo $rss;
   5.118 +?>