CORE-POS/IS4C

View on GitHub
fannie/modules/plugins2.0/CalendarPlugin/CalendarFeed.php

Summary

Maintainability
C
1 day
Test Coverage
<?php

include(dirname(__FILE__) . '/../../../config.php');
if (!class_exists('FannieAPI')) {
    include_once(dirname(__FILE__) . '/../../../classlib2.0/FannieAPI.php');
}

class CalendarFeed extends FannieRESTfulPage
{
    protected $window_dressing = false;
    public $discoverable = false;

    public function preprocess()
    {
        $this->__routes[] = 'get<id><token>';

        return parent::preprocess();
    }

    public function get_id_token_handler()
    {
        $dbc = CalendarPluginDB::get();
        $cal = new CalendarsModel($dbc); 
        $cal->calendarID($this->id);
        if (!$cal->load()) {
            header("HTTP/1.0 404 Not Found");
            echo "404";
            return false;
        }

        $token = sha1($cal->calendarID() . 'FannieCalendar' . $cal->name());
        if ($token != $this->token) {
            header("HTTP/1.0 403 Forbidden");
            echo "403";
            return false;
        }

        $filename = dirname(__FILE__) . '/ics/' . $this->token . '.ics';
        if (!file_exists($filename) || $cal->modified() == 1 || FormLib::get('export') == 1) {
            $this->writeIcal($this->id, $filename);
            $cal->modified(0);
            $cal->save();
        }

        return true;
    }

    private function writeICal($id, $filename)
    {
        global $FANNIE_OP_DB;
        $dbc = CalendarPluginDB::get();
        $cal = new CalendarsModel($dbc); 
        $cal->calendarID($id);
        $cal->load();
         
        $query = '
            SELECT m.eventID,
                m.eventDate,
                m.eventText,
                m.uid,
                u.real_name,
                u.name
            FROM monthview_events AS m
                LEFT JOIN ' . $FANNIE_OP_DB . $dbc->sep() . 'Users AS u ON m.uid=u.uid
            WHERE m.calendarID = ?';
        if (FormLib::get('export') != 1) {
            $query .= ' AND m.eventDate >= ' . $dbc->curdate();
        }
        $query .= ' ORDER BY eventDate DESC';
        $prep = $dbc->prepare($query);
        $res = $dbc->execute($prep, array($id));

        $fp = fopen($filename, 'w');
        fwrite($fp, "BEGIN:VCALENDAR\r\n");
        fwrite($fp, "VERSION:2.0\r\n");
        fwrite($fp, "PRODID:-//FannieCalendarPlugin//NONSGML v1.0//EN\r\n");
        fwrite($fp, "X-WR-CALNAME:" . $cal->name() . "\r\n");
        fwrite($fp, "CALSCALE:GREGORIAN\r\n");
        $now = gmdate('Ymd') . 'T' . gmdate('His') . 'Z';
        while ($row = $dbc->fetch_row($res)) {
            $times = $this->getTime($row['eventText']);
            $date_stem = date('Y-m-d', strtotime($row['eventDate']));
            fwrite($fp, "BEGIN:VEVENT\r\n");
            fwrite($fp, "UID:" . sha1($row['eventID']) . '@' . $_SERVER['HTTP_HOST'] . "\r\n");
            if ($times && strtotime($date_stem . ' ' . $times['start'] . ':00') && strtotime($date_stem . ' ' . $times['end'] . ':00')) {
                $startTime = strtotime($date_stem . ' ' . $times['start'] . ':00');
                $endTime = strtotime($date_stem . ' ' . $times['end'] . ':00');
                fwrite($fp, "DTSTART:" . gmdate('Ymd\THis\Z', $startTime) . "\r\n");
                fwrite($fp, "DTEND:" . gmdate('Ymd\THis\Z', $endTime) . "\r\n");
            } else {
                fwrite($fp, "DTSTART;VALUE=DATE:" . date('Ymd', strtotime($row['eventDate'])) . "\r\n");
            }
            fwrite($fp, "DTSTAMP:" . $now . "\r\n");
            $row['eventText'] = $this->br2nl($row['eventText']);
            fwrite($fp, "DESCRIPTION:" . $this->escapeString($row['eventText']) . "\r\n");
            $summary = explode("\n", $row['eventText'], 2);
            fwrite($fp, "SUMMARY:" . $this->escapeString($summary[0]) . "\r\n");
            fwrite($fp, "ORGANIZER;CN=" . $row['real_name'] . ":" . $row['name'] . '@' . $_SERVER['HTTP_HOST'] . "\r\n");
            fwrite($fp, "LAST-MODIFIED:" . $now . "\r\n");
            fwrite($fp, "END:VEVENT\r\n");
        }
        fwrite($fp, "END:VCALENDAR\r\n");
    }

    private function br2nl($string)
    {
        return preg_replace('/\<br(\s*)?\/?\>/i', '\\n', $string);
    }

    /**
      Extract a time or time range from a string
      @param $string input value
      @return [keyed array]
        start => starting unix timestamp
    */
    private function getTime($string)
    {
        $regex = '/(\d{1,2}\s{0,2}(?:am|pm|(?::\d\d)){0,1}\s{0,2}(?:am|pm){0,1})(?:\s{0,2}(?:-|to|till|until)\s{0,2}(\d{1,2}\s{0,2}(?:am|pm|(?::\d\d)){0,1}\s{0,2}(?:am|pm){0,1}))?/i';
        $ret = false;
        if (preg_match($regex, $string, $matches)) {
            $hour1 = trim($matches[1]);
            $hour1_number = preg_replace('/^(\d+)\D?.*$/', '$1', $hour1);
            if ($hour1_number == 12) {
                $hour1_number = 0;
            }
            $hour2 = isset($matches[2]) ? $matches[2] : false;
            $hour2_number = $hour2 ? preg_replace('/^(\d+)\D?.*$/', '$1', $hour2) : false;
            if ($hour2_number == 12) {
                $hour2_number = 0;
            }
            if (!preg_match('/(am|pm)/i', $hour1)) {
                if ($hour2 !== false) {
                    if (preg_match('/am/i', $hour2) && $hour1_number < $hour2_number) {
                        $hour1 .= 'am';
                    } elseif (preg_match('/am/i', $hour2) && $hour1_number > $hour2_number) {
                        $hour1 .= 'pm';
                    } elseif (preg_match('/pm/i', $hour2) && $hour1_number < $hour2_number) {
                        $hour1 .= 'pm';
                    } elseif (preg_match('/pm/i', $hour2) && $hour1_number > $hour2_number) {
                        $hour1 .= 'am';
                    } elseif ($hour1_number < $hour2_number) {
                        $hour1 .= 'pm';
                        $hour2 .= 'am'; 
                    } elseif ($hour1_number > $hour2_number) {
                        $hour1 .= 'am';
                        $hour2 .= 'pm'; 
                    }
                } else {
                    $hour1 = false; 
                }
            }

            if ($hour2 && preg_match('/pm/i', $hour2)) {
                $hour2_number += 12;
            }
            if ($hour1 && preg_match('/pm/i', $hour1)) {
                $hour1_number += 12;
            }
            if ($hour1) {
                $hour1 = preg_replace('/^\d+(:?\d*)\D*$/', str_pad($hour1_number, 2, '0', STR_PAD_LEFT) . '$1', $hour1);
                if (!preg_match('/:/', $hour1)) {
                    $hour1 .= ':00';
                }
                if ($hour2 === false) {
                    $hour2_number = $hour1_number+1;
                    $hour2 = str_pad($hour2_number, 2, '0', STR_PAD_LEFT) . ':00';
                } else {
                    $hour2 = preg_replace('/^\d+(:?\d*)\D*$/', str_pad($hour2_number, 2, '0', STR_PAD_LEFT) . '$1', $hour2);
                    if (!preg_match('/:/', $hour2)) {
                        $hour2 .= ':00';
                    }
                }

                $ret = array('start'=>$hour1, 'end'=>$hour2);
            }
        } 

        return $ret;
    }

    // Escapes a string of characters
    private function escapeString($string) {
        return preg_replace('/([\,;])/','\\\$1', $string);
    }

    public function get_id_token_view()
    {
        $filename = dirname(__FILE__) . '/ics/' . $this->token . '.ics';
        header('Content-type: text/calendar; charset=utf-8');
        header('Content-Disposition: attachment; filename=' . time() . '-' . basename($filename));
        header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + (60*15))); 
        header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T', filemtime($filename)));
        header('ETag: ' . sha1_file($filename));
        header('Cache-Control: private');
        header_remove('Pragma');
        
        readfile($filename);

        exit; // avoid trailing close html tag
    }
}

FannieDispatch::conditionalExec();