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 +?>