avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 1 | <?php |
| 2 | class gtfs { |
| 3 | //private static $files = ["calendar_dates", "calendar", "routes", "stop_times", "stops", "trips"]; |
| 4 | |
| 5 | private $db; |
| 6 | |
| 7 | private static $dow = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]; |
| 8 | |
| 9 | function __construct($path = null) { |
| 10 | global $conf; |
| 11 | |
| 12 | try { |
| 13 | $this->db = new PDO('sqlite:'.($conf["databaseFile"])); |
| 14 | } catch (PDOException $e) { |
| 15 | die("SQLite error: $e\n"); |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | static function timeSinceMidnight() { |
| 20 | //return 8*60*60 + 9*60; //TESTING |
| 21 | return (time() - mktime(0, 0, 0)); |
| 22 | } |
| 23 | |
| 24 | static function today() { |
| 25 | return date("Ymd"); |
| 26 | } |
| 27 | |
| 28 | static function time2seconds($time) { |
| 29 | $timeSinceMidnight = self::timeSinceMidnight(); |
| 30 | |
| 31 | $boom = explode(":", $time); |
| 32 | if (count($boom) != 3) return null; |
| 33 | |
| 34 | return ((($boom[0]*60) + $boom[1])*60 + $boom[2]) % (24*60*60); |
| 35 | } |
| 36 | |
| 37 | private function fetchAll($sql) { |
| 38 | $query = $this->db->query($sql); |
| 39 | if (!$query) return false; |
| 40 | |
| 41 | return $query->fetchAll(PDO::FETCH_ASSOC); |
| 42 | } |
| 43 | |
| 44 | private function fetchAllPrepared($sql, $values) { |
| 45 | $query = $this->db->prepare($sql); |
| 46 | if (!$query) return false; |
| 47 | |
| 48 | $query->execute($values); |
| 49 | return $query->fetchAll(PDO::FETCH_ASSOC); |
| 50 | } |
| 51 | |
| 52 | private function fetchTable($table, $filters = [], $orderedField = null) { |
| 53 | $order = ($orderedField === null ? "" : " ORDER BY $orderedField"); |
| 54 | |
| 55 | if (!count($filters)) { |
| 56 | return $this->fetchAll("SELECT * FROM $table".$order); |
| 57 | } |
| 58 | |
| 59 | $whereConditions = []; |
| 60 | $values = []; |
| 61 | foreach ($filters as $filter) { |
| 62 | $whereConditions[] = $filter[0]." = ?"; |
| 63 | $values[] = $filter[1]; |
| 64 | } |
| 65 | |
| 66 | return $this->fetchAllPrepared("SELECT * FROM $table WHERE ".implode(" AND ", $whereConditions).$order, $values); |
| 67 | } |
| 68 | |
| 69 | function getRoutes() { |
| 70 | return $this->fetchTable("routes"); |
| 71 | } |
| 72 | |
| 73 | function getTrips($route) { |
| 74 | return $this->fetchTable("trips", [["route_id", $route]]); |
| 75 | } |
| 76 | |
| 77 | function getStations($ordered = false) { |
| 78 | return $this->fetchTable("stops", [["location_type", Gtfs\Stop\LocationType::STATION]], ($ordered ? "stop_name" : null)); |
| 79 | } |
| 80 | |
| 81 | function getStop($stop) { |
| 82 | $results = $this->fetchTable("stops", [["stop_id", $stop]]); |
| 83 | |
| 84 | if (!count($results)) return null; |
| 85 | |
| 86 | return $results[0]; |
| 87 | } |
| 88 | |
| 89 | function getPlatforms($stop) { |
| 90 | $results = $this->fetchTable("stops", [["parent_station", $stop], ["location_type", Gtfs\Stop\LocationType::STOP]], "stop_id"); |
| 91 | |
| 92 | return $results; |
| 93 | } |
| 94 | |
avm99963 | dfd7bd5 | 2020-01-27 03:37:54 +0100 | [diff] [blame] | 95 | const TIME_LIMIT = 30; |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 96 | function getStopTimes($stop, $timeLimit = self::TIME_LIMIT) { |
| 97 | $stops = $this->getPlatforms($stop); |
| 98 | |
| 99 | $values = []; |
| 100 | foreach ($stops as $s) { |
| 101 | $values[] = $s["stop_id"]; // Stops |
| 102 | } |
| 103 | |
| 104 | $rdow = (int)date("w"); |
| 105 | $dow = self::$dow[$rdow]; // Today's day of week |
| 106 | $dow2 = self::$dow[($rdow + 1) % 7]; // Tomorrow's day of week |
| 107 | |
| 108 | if (!count($stops)) return []; |
| 109 | |
| 110 | $sql = "SELECT st.*, t.*, r.*, c.*, cd.*, strftime('%Y%m%d', 'now', 'localtime') as today, strftime('%Y%m%d', 'now', 'localtime', '1 day') as tomorrow, time('now', 'localtime') as now |
| 111 | FROM stop_times st |
| 112 | INNER JOIN trips t |
| 113 | ON st.trip_id = t.trip_id |
| 114 | INNER JOIN routes r |
| 115 | ON t.route_id = r.route_id |
| 116 | LEFT JOIN calendar c |
| 117 | ON t.service_id = c.service_id |
| 118 | LEFT JOIN calendar_dates cd |
| 119 | ON t.service_id = cd.service_id |
| 120 | WHERE |
| 121 | st.stop_id IN (".implode(", ", array_fill(0, count($stops), "?")).") AND |
| 122 | ( |
| 123 | cd.service_id IS NULL OR |
| 124 | cd.exception_type = ".(int)Gtfs\CalendarDate\ExceptionType::ADDED." |
| 125 | ) AND |
| 126 | ( |
| 127 | ( |
| 128 | ( |
| 129 | ( |
| 130 | time(now) < time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 131 | st.departure_time BETWEEN time(now) AND time(now, '".(int)$timeLimit." minutes') |
| 132 | ) OR |
| 133 | ( |
| 134 | time(now) >= time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 135 | st.departure_time BETWEEN time(now) AND strftime('24:%M:%S', now, '".(int)$timeLimit." minutes') |
| 136 | ) |
| 137 | ) AND |
| 138 | ( |
| 139 | c.service_id IS NULL OR |
| 140 | ( |
| 141 | c.start_date <= today AND |
| 142 | c.end_date >= today AND |
| 143 | c.$dow = ".(int)Gtfs\Calendar\CalendarDay::AVAILABLE." |
| 144 | ) |
| 145 | ) AND |
| 146 | ( |
| 147 | cd.service_id IS NULL OR |
| 148 | cd.date = today |
| 149 | ) |
| 150 | ) OR |
| 151 | ( |
| 152 | ( |
| 153 | ( |
| 154 | time(now) < time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 155 | st.departure_time BETWEEN ((strftime('%H', now) + 24) || strftime(':%M:%S', now)) AND ((strftime('%H', now, '".(int)$timeLimit." minutes') + 24) || strftime(':%M:%S', now, '".(int)$timeLimit." minutes')) |
| 156 | ) OR |
| 157 | ( |
| 158 | time(now) >= time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 159 | st.departure_time BETWEEN time(now) AND strftime('24:%M:%S', now, '".(int)$timeLimit." minutes') |
| 160 | ) |
| 161 | ) AND |
| 162 | ( |
| 163 | c.service_id IS NULL OR |
| 164 | ( |
| 165 | c.start_date <= tomorrow AND |
| 166 | c.end_date >= tomorrow AND |
| 167 | c.$dow2 = ".(int)Gtfs\Calendar\CalendarDay::AVAILABLE." |
| 168 | ) |
| 169 | ) AND |
| 170 | ( |
| 171 | cd.service_id IS NULL OR |
| 172 | cd.date = tomorrow |
| 173 | ) |
| 174 | ) |
| 175 | ) |
| 176 | ORDER BY departure_time ASC"; |
| 177 | |
| 178 | $result = $this->fetchAllPrepared($sql, $values); |
| 179 | if ($result === false) { |
| 180 | echo implode("\n", $this->db->errorInfo()); |
| 181 | exit(); |
| 182 | } |
| 183 | |
| 184 | return $result; |
| 185 | } |
| 186 | |
| 187 | function __destruct() { |
| 188 | $this->db = null; |
| 189 | } |
| 190 | } |