horde/mapi
Composer 安装命令:
composer require horde/mapi
包简介
MAPI utility library
README 文档
README
MAPI utility library – helper library for Microsoft MAPI data structures in the Horde Framework.
| Package | horde/mapi |
| Upstream | github.com/horde/mapi |
| License | LGPL-2.1 |
| Author | Michael J Rubinsky |
| PHP | ^8.1 |
| Dependencies | horde/date, horde/exception, PHP extension bcmath |
What is MAPI?
MAPI (Messaging Application Programming Interface) is Microsoft's API for messaging, calendars, and contacts—primarily in Exchange and Outlook. In Horde, this library is not a full MAPI client or Exchange connector. It provides binary format helpers used by Microsoft protocols, especially Exchange ActiveSync.
Typical use cases in Horde:
- Encode/decode timezones as MAPI
TIME_ZONE_INFORMATIONblobs (ActiveSync) - Convert Global Object Identifier (GOID) ↔ iCalendar UID (appointments, meeting requests)
- Convert Windows FILETIME to Unix timestamps
Architecture
The library is intentionally small and consists of three classes:
lib/Horde/
├── Mapi.php → Horde_Mapi (static helpers)
└── Mapi/
├── Timezone.php → Horde_Mapi_Timezone
└── Exception.php → Horde_Mapi_Exception
Horde_Mapi
General MAPI helper functions (all static):
| Method | Description |
|---|---|
isLittleEndian() |
Checks the system's byte order |
chbo($num) |
Reverses the byte order of an integer (for big-endian systems) |
getUidFromGoid($goid) |
Extracts a UID from a Base64-encoded GOID |
createGoid($uid) |
Creates a Base64-encoded GOID from a UID |
filetimeToUnixtime($ft) |
Converts binary Windows FILETIME to a Unix timestamp |
MAPI structures are encoded in little-endian order. On big-endian systems, values are adjusted with chbo() before packing/unpacking.
filetimeToUnixtime() requires the PHP bcmath extension because FILETIME uses 64-bit values that PHP cannot represent natively. Without bcmath, it returns -1.
Horde_Mapi_Timezone
Converts between Microsoft's timezone blob and PHP/IANA timezones.
Microsoft defines timezones as a binary TIME_ZONE_INFORMATION structure (bias, standard/daylight names, SYSTEMTIME transitions, etc.). ActiveSync transmits this structure Base64-encoded in the WBXML protocol.
| Method | Direction | Description |
|---|---|---|
getOffsetsFromSyncTZ($data) |
MAPI blob → array | Decodes an ActiveSync timezone blob into an offset hash |
getSyncTZFromOffsets($offsets) |
array → MAPI blob | Builds an ActiveSync-compatible timezone blob |
getOffsetsFromDate(Horde_Date $date) |
IANA TZ → array | Derives offsets from a Horde_Date/timezone |
getTimezone($offsets, $expectedTimezone) |
MAPI blob/array → IANA | Guesses the matching Olson timezone |
getListOfTimezones($offsets, $expectedTimezone) |
MAPI blob/array → array | All matching IANA identifiers |
Reverse mapping (MAPI offsets → IANA timezone) is ambiguous: multiple timezones can share the same offsets. You can pass $expectedTimezone to prefer a specific match; otherwise Horde_Date::getTimezoneAlias() picks an alias.
Logic for detecting the nth weekday occurrence in a month (e.g. "second Sunday in March") is partly inspired by the Tine 2.0 project.
Horde_Mapi_Exception
Base exception class (extends Horde_Exception_Wrapped), e.g. for missing bcmath extension or no matching timezone.
How it works
1. Timezone blob (ActiveSync)
Horde_Date / IANA timezone
│
▼
getOffsetsFromDate() ← reads DST/STD transitions via DateTimeZone
│
▼
getSyncTZFromOffsets() ← pack() into TIME_ZONE_INFORMATION, base64_encode()
│
▼
ActiveSync WBXML (Appointment.timezone)
Reverse direction when receiving:
Base64 timezone blob from client
│
▼
getOffsetsFromSyncTZ() ← base64_decode(), unpack()
│
▼
getTimezone() / getListOfTimezones() ← match against all IANA zones
│
▼
e.g. "Europe/Berlin"
2. Global Object Identifier (GOID)
GOIDs uniquely identify appointments across Exchange/Outlook. The library supports two formats:
- Outlook style: hex representation of the entire GOID, bytes 17–20 set to zero
- vCal style:
vCal-Uidmarker in the blob, UID as plain text after it
iCalendar UID ←→ createGoid() / getUidFromGoid() ←→ Base64 GOID
3. FILETIME
Windows stores timestamps as 64-bit counters in 100-ns ticks since 1 Jan 1601 UTC. Conversion steps:
- Hex string from binary data
- Flip endianness (
_flipEndian) - Hex → bcmath integer (
_hexToBcint) - Subtract epoch offset and divide by 10,000,000 (
_win64ToUnix)
Usage in a Horde installation
horde/mapi is used mainly indirectly via ActiveSync:
| Module | File | Usage |
|---|---|---|
| ActiveSync | Horde/ActiveSync/Message/Appointment.php |
setTimezone() / getTimezone() for appointment sync |
| ActiveSync | Horde/ActiveSync/Message/MeetingRequest.php |
createGoid() for meeting UIDs, timezone parsing |
| Kronolith | lib/Event.php |
_handleEas16Exception() – resolve timezone from ActiveSync message |
These functions previously lived in Horde_ActiveSync_Utils and Horde_ActiveSync_Timezone; since Horde 6 they were moved into horde/mapi (the old classes are marked @deprecated).
Examples
Create a timezone blob
$date = new Horde_Date(time(), 'Europe/Berlin'); $offsets = Horde_Mapi_Timezone::getOffsetsFromDate($date); $blob = Horde_Mapi_Timezone::getSyncTZFromOffsets($offsets); // $blob → Base64 string for ActiveSync
Parse a timezone blob
$parser = new Horde_Mapi_Timezone(); $tz = $parser->getTimezone($blob, 'Europe/Berlin'); // $tz → e.g. "Europe/Berlin"
GOID ↔ UID
$goid = Horde_Mapi::createGoid('{81412D3C-2A24-4E9D-B20E-11F7BBE92799}'); $uid = Horde_Mapi::getUidFromGoid($goid);
Convert FILETIME
$binaryFiletime = /* from MAPI pTypDate property */; $unix = Horde_Mapi::filetimeToUnixtime($binaryFiletime);
Installation
Via Composer (in Horde, typically as a framework dependency):
composer require horde/mapi
In this installation: dev-FRAMEWORK_6_0 (Horde Framework 6).
Tests
cd vendor/horde/mapi
vendor/bin/phpunit
Tests live under test/Unnamespaced/ (MapiTest.php, TimezoneTest.php) with fixtures for GOIDs and FILETIME.
Further reading
horde/mapi 适用场景与选型建议
horde/mapi 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.68k 次下载、GitHub Stars 达 1, 最近一次更新时间为 2023 年 12 月 25 日, 在 PHP 生态内属于活跃度较高的组件。
我们在过去多个企业项目中使用过 horde/mapi 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 horde/mapi 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
统计信息
- 总下载量: 1.68k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 7
- 依赖项目数: 3
- 推荐数: 1
其他信息
- 授权协议: LGPL-2.1-only
- 更新时间: 2023-12-25