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) { |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 97 | $platforms = $this->getPlatforms($stop); |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 98 | |
| 99 | $values = []; |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 100 | foreach ($platforms as $i => $s) { |
| 101 | $values[":stop".(int)$i] = $s["stop_id"]; // Stops |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 102 | } |
| 103 | |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 104 | $stopParameters = array_keys($values); |
| 105 | |
| 106 | $rdow = (int)(new DateTime("now"))->format("w"); |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 107 | $dow = self::$dow[$rdow]; // Today's day of week |
| 108 | $dow2 = self::$dow[($rdow + 1) % 7]; // Tomorrow's day of week |
| 109 | |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 110 | $values[":today"] = (int)(new DateTime("now"))->format("Ymd"); // Today's date |
| 111 | $values[":tomorrow"] = (int)(new DateTime("tomorrow"))->format("Ymd"); // Tomorrow's date |
| 112 | $values[":now"] = (new DateTime("now"))->format("H:i:s"); |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 113 | |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 114 | if (!count($platforms)) return []; |
| 115 | |
| 116 | $sql = "SELECT st.*, t.*, r.*, c.*, cd.* |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 117 | FROM stop_times st |
| 118 | INNER JOIN trips t |
| 119 | ON st.trip_id = t.trip_id |
| 120 | INNER JOIN routes r |
| 121 | ON t.route_id = r.route_id |
| 122 | LEFT JOIN calendar c |
| 123 | ON t.service_id = c.service_id |
| 124 | LEFT JOIN calendar_dates cd |
| 125 | ON t.service_id = cd.service_id |
| 126 | WHERE |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 127 | st.stop_id IN (".implode(", ", $stopParameters).") AND |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 128 | ( |
| 129 | cd.service_id IS NULL OR |
| 130 | cd.exception_type = ".(int)Gtfs\CalendarDate\ExceptionType::ADDED." |
| 131 | ) AND |
| 132 | ( |
| 133 | ( |
| 134 | ( |
| 135 | ( |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 136 | time(:now) < time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 137 | st.departure_time BETWEEN time(:now) AND time(:now, '".(int)$timeLimit." minutes') |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 138 | ) OR |
| 139 | ( |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 140 | time(:now) >= time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 141 | st.departure_time BETWEEN time(:now) AND strftime('24:%M:%S', :now, '".(int)$timeLimit." minutes') |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 142 | ) |
| 143 | ) AND |
| 144 | ( |
| 145 | c.service_id IS NULL OR |
| 146 | ( |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 147 | c.start_date <= :today AND |
| 148 | c.end_date >= :today AND |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 149 | c.$dow = ".(int)Gtfs\Calendar\CalendarDay::AVAILABLE." |
| 150 | ) |
| 151 | ) AND |
| 152 | ( |
| 153 | cd.service_id IS NULL OR |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 154 | cd.date = :today |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 155 | ) |
| 156 | ) OR |
| 157 | ( |
| 158 | ( |
| 159 | ( |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 160 | time(:now) < time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 161 | 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')) |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 162 | ) OR |
| 163 | ( |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 164 | time(:now) >= time('00:00:00', '-".(int)$timeLimit." minutes') AND |
| 165 | st.departure_time BETWEEN time(:now) AND strftime('24:%M:%S', :now, '".(int)$timeLimit." minutes') |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 166 | ) |
| 167 | ) AND |
| 168 | ( |
| 169 | c.service_id IS NULL OR |
| 170 | ( |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 171 | c.start_date <= :tomorrow AND |
| 172 | c.end_date >= :tomorrow AND |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 173 | c.$dow2 = ".(int)Gtfs\Calendar\CalendarDay::AVAILABLE." |
| 174 | ) |
| 175 | ) AND |
| 176 | ( |
| 177 | cd.service_id IS NULL OR |
avm99963 | 78011ca | 2020-07-05 13:49:26 +0200 | [diff] [blame^] | 178 | cd.date = :tomorrow |
avm99963 | 99bb77c | 2020-01-27 03:15:08 +0100 | [diff] [blame] | 179 | ) |
| 180 | ) |
| 181 | ) |
| 182 | ORDER BY departure_time ASC"; |
| 183 | |
| 184 | $result = $this->fetchAllPrepared($sql, $values); |
| 185 | if ($result === false) { |
| 186 | echo implode("\n", $this->db->errorInfo()); |
| 187 | exit(); |
| 188 | } |
| 189 | |
| 190 | return $result; |
| 191 | } |
| 192 | |
| 193 | function __destruct() { |
| 194 | $this->db = null; |
| 195 | } |
| 196 | } |