diff --git a/lib/input/json.php b/lib/input/json.php index 3c0a5db..e161c3b 100644 --- a/lib/input/json.php +++ b/lib/input/json.php @@ -1,312 +1,316 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class kolab_api_input_json extends kolab_api_input { /** * Get request data (JSON) * * @param string Expected object type * @param bool Disable filters application * @param array Original object data (set on update requests) * * @return array Request data */ public function input($type = null, $disable_filters = false, $original = null) { if ($this->input_body === null) { $data = file_get_contents('php://input'); $data = trim($data); if (!empty($data) && $this->api->config->get('kolab_api_debug')) { rcube::console($data); } $this->input_body = $data = json_decode($data, true); + + if ($data === null) { + throw new kolab_api_exception(kolab_api_exception::INVALID_REQUEST, null, "Malformed JSON input"); + } } if (!$disable_filters) { if ($this->filter) { if (!empty($original)) { // convert object data into API format $data = $this->api->get_object_data($original, $type); } $this->filter->input_body($this->input_body, $type, $data); } // convert input to internal kolab_storage format if ($type) { $class = "kolab_api_input_json_$type"; if (class_exists($class)) { $model = new $class; $model->input($this->input_body, $original); } } } return $this->input_body; } /** * Convert xCard/xCal date and date-time into internal DateTime * * @param array|string Date or Date-Time * * @return DateTime */ public static function to_datetime($input) { if (empty($input)) { return; } if (is_array($input)) { if ($input['date-time']) { if ($input['parameters']['tzid']) { $tzid = str_replace('/kolab.org/', '', $input['parameters']['tzid']); } else { $tzid = 'UTC'; } $datetime = $input['date-time']; try { $timezone = new DateTimeZone($tzid); } catch (Exception $e) {} } else if ($input['timestamp']) { $datetime = $input['timestamp']; } else if ($input['date']) { $datetime = $input['date']; $is_date = true; } else { return; } } else { $datetime = $input; $is_date = preg_match('/^[0-9]{4}-?[0-9]{2}-?[0-9]{2}$/', $input); } try { $dt = new DateTime($datetime, $timezone ?: new DateTimeZone('UTC')); } catch (Exception $e) { return; } // Horde_Date (via libcalendaring) doesn't like some timezones // @TODO: don't use Horde_Date or fix it there if ($dt->getTimezone()->getName() == 'Z') { $dt->setTimezone(new DateTimeZone('UTC')); } if ($is_date) { $dt->_dateonly = true; $dt->setTime(0, 0, 0); } return $dt; } /** * Convert PHP DateTime into xCard/xCal date or date-time * * @param DateTime $datetime DateTime object * @param string $timezone Timezone identifier * * @return array */ public static function from_datetime($datetime, $timezone = null) { $format = $datetime->_dateonly ? 'Y-m-d' : 'Y-m-d\TH:i:s'; $type = $datetime->_dateonly ? 'date' : 'date-time'; if ($timezone && $timezone != 'UTC') { try { $tz = new DateTimeZone($timezone); $datetime->setTimezone($tz); $result['parameters'] = array( 'tzid' => '/kolab.org/' . $timezone ); } catch (Exception $e) { } } else if (!$datetime->_dateonly) { $format .= '\Z'; } $result[$type] = $datetime->format($format); return $result; } /** * Add x-custom fields to the result */ public static function add_x_custom($data, &$result) { if (array_key_exists('x-custom', (array) $data)) { $value = (array) $data['x-custom']; foreach ((array) $value as $idx => $v) { if ($v['identifier'] && $v['value'] !== null) { $value[$idx] = array($v['identifier'], $v['value']); } else { unset($value[$idx]); } } $result['x-custom'] = $value; } } /** * Parse mailto URI, e.g. attendee/cal-address property * * @param string $uri Mailto: uri * @param string $params Element parameters * * @return string E-mail address */ public static function parse_mailto_uri($uri, &$params = array()) { if (strpos($uri, 'mailto:') === 0) { $uri = substr($uri, 7); $uri = rawurldecode($uri); $emails = rcube_mime::decode_address_list($uri, 1, true, null, false); $email = $emails[1]; if (!empty($email['mailto'])) { if (empty($params['cn']) && !empty($email['name'])) { $params['cn'] = $email['name']; } return $email['mailto']; } } } /** * Parse attendees property input * * @param array $attendees Attendees list * * @return array Attendees list in kolab_format_xcal format */ public static function parse_attendees($attendees) { foreach ((array) $attendees as $idx => $attendee) { $params = $attendee['parameters']; $email = kolab_api_input_json::parse_mailto_uri($attendee['cal-address'], $params); foreach (array('to', 'from') as $val) { foreach ((array) $params['delegated-' . $val] as $del) { if ($del_email = kolab_api_input_json::parse_mailto_uri($del, $params)) { $delegated[$val][] = $del_email; } } } if ($email) { $attendees[$idx] = array_filter(array( 'email' => $email, 'name' => $params['cn'], 'status' => $params['partstat'], 'role' => $params['role'], 'rsvp' => (bool) $params['rsvp'] || strtoupper($params['rsvp']) === 'TRUE', 'cutype' => $params['cutype'], 'dir' => $params['dir'], 'delegated-to' => $delegated['to'], 'delegated-from' => $delegated['from'], )); } else { unset($attendees[$idx]); } } return $attendees; } /** * Handle recurrence rule input * * @param array $data Input data * @param array $result Result data */ public static function parse_recurrence($data, &$result) { if (array_key_exists('rrule', $data)) { $result['recurrence'] = array(); $recur_keys = array( 'freq', 'interval', 'count', 'bymonth', 'bymonthday', 'byday', 'byyearday', 'bysetpos', 'byhour', 'byminute', 'bysecond', 'wkst', ); foreach ($recur_keys as $key) { if ($data['rrule']['recur'][$key]) { $result['recurrence'][strtoupper($key)] = $data['rrule']['recur'][$key]; } } if ($data['rrule']['recur']['until']) { $result['recurrence']['UNTIL'] = self::to_datetime($data['rrule']['recur']['until']); } } // Recurrence: deleted exceptions (EXDATE) if (array_key_exists('exdate', $data)) { $result['recurrence']['EXDATE'] = array(); if (!empty($data['exdate']['date'])) { $result['recurrence']['EXDATE'] = (array) $data['exdate']['date']; } else if (!empty($data['exdate']['date-time'])) { $result['recurrence']['EXDATE'] = (array) $data['exdate']['date-time']; } } // Recurrence (RDATE) if (array_key_exists('rdate', $data)) { $result['recurrence']['RDATE'] = array(); if (!empty($data['rdate']['date'])) { $result['recurrence']['RDATE'] = (array) $data['rdate']['date']; } else if (!empty($data['exdate']['date-time'])) { $result['recurrence']['RDATE'] = (array) $data['rdate']['date-time']; } } } }