/** * Turns the object back into a serialized blob. * * @return string */ public function serialize() { // We need to kick in a special type of encoding, if it's a 2.1 vcard. if ($this->root->getDocumentType() !== Document::VCARD21) { return parent::serialize(); } $val = $this->getParts(); if (isset($this->minimumPropertyValues[$this->name])) { $val = array_pad($val, $this->minimumPropertyValues[$this->name], ''); } // Imploding multiple parts into a single value, and splitting the // values with ;. if (count($val) > 1) { foreach ($val as $k => $v) { $val[$k] = str_replace(';', '\\;', $v); } $val = implode(';', $val); } else { $val = $val[0]; } $str = $this->name; if ($this->group) { $str = $this->group . '.' . $this->name; } foreach ($this->parameters as $param) { if ($param->getValue() === 'QUOTED-PRINTABLE') { continue; } $str .= ';' . $param->serialize(); } // If the resulting value contains a \n, we must encode it as // quoted-printable. if (strpos($val, "\n") !== false) { $str .= ';ENCODING=QUOTED-PRINTABLE:'; $lastLine = $str; $out = null; // The PHP built-in quoted-printable-encode does not correctly // encode newlines for us. Specifically, the \r\n sequence must in // vcards be encoded as =0D=OA and we must insert soft-newlines // every 75 bytes. for ($ii = 0; $ii < strlen($val); $ii++) { $ord = ord($val[$ii]); // These characters are encoded as themselves. if ($ord >= 32 && $ord <= 126) { $lastLine .= $val[$ii]; } else { $lastLine .= '=' . strtoupper(bin2hex($val[$ii])); } if (strlen($lastLine) >= 75) { // Soft line break $out .= $lastLine . "=\r\n "; $lastLine = null; } } if (!is_null($lastLine)) { $out .= $lastLine . "\r\n"; } return $out; } else { $str .= ':' . $val; $out = ''; while (strlen($str) > 0) { if (strlen($str) > 75) { $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n"; $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8'); } else { $out .= $str . "\r\n"; $str = ''; break; } } return $out; } }
/** * @brief Data structure of properties * @param object $property * @return associative array * * returns an associative array with * ['name'] name of property * ['value'] htmlspecialchars escaped value of property * ['parameters'] associative array name=>value * ['checksum'] checksum of whole property * NOTE: $value is not escaped anymore. It shouldn't make any difference * but we should look out for any problems. */ public static function structureProperty(\Sabre\VObject\Property $property) { if (!in_array($property->name, App::$index_properties)) { return; } $value = $property->getValue(); if ($property->name == 'ADR' || $property->name == 'N' || $property->name == 'ORG' || $property->name == 'CATEGORIES') { $value = $property->getParts(); if ($property->name == 'CATEGORIES') { $value = str_replace(';', ',', $value); } if ($property->name == 'N') { //$value = stripslashes($value); // \OCP\Util::writeLog('contactsplus','NAME VAL: '.$value, \OCP\Util::DEBUG); } $value = array_map('trim', $value); } elseif ($property->name == 'BDAY') { if (strlen($value) >= 8 && is_int(substr($value, 0, 4)) && is_int(substr($value, 4, 2)) && is_int(substr($value, 6, 2))) { $value = substr($value, 0, 4) . '-' . substr($value, 4, 2) . '-' . substr($value, 6, 2); } else { if ($value[5] !== '-' || $value[7] !== '-') { try { // Skype exports as e.g. Jan 14, 1996 $date = new \DateTime($value); $value = $date->format('Y-m-d'); } catch (\Exception $e) { \OCP\Util::writeLog('contactsplus', __METHOD__ . ' Error parsing date: ' . $value, \OCP\Util::DEBUG); return; } } } } elseif ($property->name == 'PHOTO') { $value = true; } elseif ($property->name == 'IMPP') { if (strpos($value, ':') !== false) { $value = explode(':', $value); $protocol = array_shift($value); if (!isset($property['X-SERVICE-TYPE'])) { $property['X-SERVICE-TYPE'] = strtoupper($protocol); } $value = implode('', $value); } } if (is_string($value)) { $value = strtr($value, array('\\,' => ',', '\\;' => ';')); } $temp = array('value' => $value, 'parameters' => array()); // This cuts around a 3rd off of the json response size. if (in_array($property->name, App::$multi_properties)) { $temp['checksum'] = substr(md5($property->serialize()), 0, 8); } foreach ($property->parameters as $parameter) { // Faulty entries by kaddressbook // Actually TYPE=PREF is correct according to RFC 2426 // but this way is more handy in the UI. Tanghus. if ($parameter->name == 'TYPE' && strtoupper($parameter->getValue()) == 'PREF') { $parameter->name = 'PREF'; $parameter->setValue('1'); } // NOTE: Apparently Sabre_VObject_Reader can't always deal with value list parameters // like TYPE=HOME,CELL,VOICE. Tanghus. // TODO: Check if parameter is has commas and split + merge if so. if ($parameter->name == 'TYPE') { $pvalue = $parameter->getValue(); if (is_string($pvalue) && strpos($pvalue, ',') !== false) { $pvalue = array_map('trim', explode(',', $pvalue)); } $pvalue = is_array($pvalue) ? $pvalue : array($pvalue); if (isset($temp['parameters'][$parameter->name])) { $temp['parameters'][$parameter->name][] = \OCP\Util::sanitizeHTML($pvalue); } else { $temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($pvalue); } } else { //$value = strtr($value, array('\,' => ',', '\;' => ';')); $temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($parameter->getValue()); } } return $temp; }
/** * @brief Get data structure of property. * @param \Sabre\VObject\Property $property * @return associative array * * returns an associative array with * ['name'] name of property * ['value'] htmlspecialchars escaped value of property * ['parameters'] associative array name=>value * ['checksum'] checksum of whole property * NOTE: $value is not escaped anymore. It shouldn't make any difference * but we should look out for any problems. */ public static function serializeProperty(\Sabre\VObject\Property $property) { if (!in_array($property->name, Properties::$index_properties)) { return; } $value = $property->value; if ($property->name == 'ADR' || $property->name == 'N' || $property->name == 'ORG' || $property->name == 'CATEGORIES') { $value = $property->getParts(); $value = array_map('trim', $value); } elseif ($property->name == 'BDAY') { if (strpos($value, '-') === false) { if (strlen($value) >= 8) { $value = substr($value, 0, 4) . '-' . substr($value, 4, 2) . '-' . substr($value, 6, 2); } else { return null; // Badly malformed :-( } } } elseif ($property->name == 'PHOTO') { $value = true; } elseif ($property->name == 'IMPP') { if (strpos($value, ':') !== false) { $value = explode(':', $value); $protocol = array_shift($value); if (!isset($property['X-SERVICE-TYPE'])) { $property['X-SERVICE-TYPE'] = strtoupper($protocol); } $value = implode('', $value); } } if (is_string($value)) { $value = strtr($value, array('\\,' => ',', '\\;' => ';')); } $temp = array('value' => $value, 'parameters' => array()); // This cuts around a 3rd off of the json response size. if (in_array($property->name, Properties::$multi_properties)) { $temp['checksum'] = substr(md5($property->serialize()), 0, 8); } foreach ($property->parameters as $parameter) { // Faulty entries by kaddressbook // Actually TYPE=PREF is correct according to RFC 2426 // but this way is more handy in the UI. Tanghus. if ($parameter->name == 'TYPE' && strtoupper($parameter->value) == 'PREF') { $parameter->name = 'PREF'; $parameter->value = '1'; } // NOTE: Apparently Sabre_VObject_Reader can't always deal with value list parameters // like TYPE=HOME,CELL,VOICE. Tanghus. // TODO: Check if parameter is has commas and split + merge if so. if ($parameter->name == 'TYPE') { $pvalue = $parameter->value; if (is_string($pvalue) && strpos($pvalue, ',') !== false) { $pvalue = array_map('trim', explode(',', $pvalue)); } $pvalue = is_array($pvalue) ? $pvalue : array($pvalue); if (isset($temp['parameters'][$parameter->name])) { $temp['parameters'][$parameter->name][] = \OCP\Util::sanitizeHTML($pvalue); } else { $temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($pvalue); } } else { $temp['parameters'][$parameter->name] = \OCP\Util::sanitizeHTML($parameter->value); } } return $temp; }