Contacts import aborts with TypeError when vCards have no UID (TextImporter structure)

未关闭 适合新手
#66,486 2 条评论 2 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@SebastianKrupinski 已经在做这个了。

开始于 2026年11月10日。

  • #66489 来自 @lazerg —— 未关闭
  • #66512 来自 @SebastianKrupinski —— 未关闭

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
72/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
php
领域
backend

调研方向

从 apps/dav/lib/CardDAV/Import/TextImporter.php 中的 analyze() 开始,这里没有 UID 的组件被存储为裸实例而不是列表。然后检查第 75 行附近的 ImportService::importText(),它读取 $instances[0]。修复方法是将没有 UID 的条目包装进列表,并且需要在 apps/dav/lib/CalDAV/Import/TextImporter.php 中检查同样的模式。当一张没有 UID 的 vCard 能成功导入时完成,并通过 apps/dav 导入测试中的一个测试来验证。

由索引模型根据 Issue 内容生成。

描述

bug
Bug description

Importing a .vcf file in the Contacts app ("Import contacts") fails completely ("0 of 629 imported") when the vCards have no UID property. A Google Contacts export is the typical case: none of its 629 cards had a UID.

The server log shows:

TypeError: OCA\DAV\CardDAV\Import\TextImporter::extract(): Argument #1 ($start) must be of type int, string given,
called in apps/dav/lib/CardDAV/Import/ImportService.php on line 75

(request: /ocs/v2.php/contacts/import)

Cause

In apps/dav/lib/CardDAV/Import/TextImporter.php::analyze(), a component with a UID is stored as a list of instances:

$this->structure[$componentType][$componentId][] = [$componentType, $componentId, $componentStart, $componentEnd];

A component without a UID is stored as a bare instance, not wrapped in a list:

$this->structure[$componentType][] = [$componentType, $componentId, $componentStart, $componentEnd];

ImportService::importText() expects a list of instances in both cases:

foreach ($structure['VCARD'] as $cid => $instances) {
    $instance = $instances[0];                                   // "VCARD" (string) for UID-less cards
    $sObjectContents = $importer->extract($instance[2], $instance[3]);  // "A", "R" -> TypeError

The generator throws on the first UID-less card, so the whole import is aborted.

The same pattern exists in apps/dav/lib/CalDAV/Import/TextImporter.php. There, ImportService casts the values with (int), so it does not throw, but it would read wrong byte ranges.

Steps to reproduce
  1. Create test.vcf:
    BEGIN:VCARD
    VERSION:3.0
    FN:Erika Mustermann
    N:Mustermann;Erika;;;
    TEL;TYPE=CELL:+49 170 0000000
    END:VCARD
    
  2. Contacts → Contacts settings → Import contacts → choose test.vcf.
  3. Result: "0 of 1 imported", with the TypeError above in nextcloud.log.

Adding a UID: line to each card makes the import succeed. I verified this with the original file: all 629 cards imported.

Expected behavior

vCards without a UID are imported. A UID is optional in vCard 3.0, and the CardDAV backend can generate one.

Suggested fix

Wrap the UID-less entry in a list as well, for example:

$this->structure[$componentType][] = [[$componentType, $componentId, $componentStart, $componentEnd]];

The same applies to the CalDAV TextImporter.

Versions
  • Nextcloud 35.0.2 (Docker image nextcloud:35-apache), PHP 8.5.12, MariaDB 11.4
  • Contacts app 8.9.5
  • The same code is in master, stable35 and stable34 as of today.
主要语言
PHP
星标
37.5k
派生
5.4k
平均合并
1 天 14 小时
30 天内合并 PR
648

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

nextcloud/server 的其他 Issue

查看 nextcloud/server 的全部 Issue

相似的 Issue

更多 PHP Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。