一个带有分支的实现(比单线程array('5' => array(5,7,8))
更复杂),但除非我只和一个人交流,否则对我个人来说,线程总是倾向于分支,所以我必须应对额外的复杂性。
<?php
$threads = imap_thread($imap, SE_UID);
$nodes = array( 0 => array( 'children' => array()));
$ids = array();
foreach ($threads as $key => $val) {
list($treeid,$type) = explode('.',$key);
switch($type){
case 'num':
$ids[$val] = null;
if($val==0){
$nodes[$treeid] = &$nodes[0];
} else {
if(!isset($nodes[$treeid])) $nodes[$treeid] = array();
$nodes[$treeid] = array_merge($nodes[$treeid],array(
'id' => $val,
'message' => &$ids[$val],
'treeid' => $treeid));
}
break;
case 'next':
if (0!=$val) {
if(!isset($nodes[$val])) $nodes[$val] = array('parent' => $treeid);
$nodes[$treeid][] = &$nodes[$val];
}
break;
case 'branch':
if (0!=$val) {
if(!isset($nodes[$val])) $nodes[$val] = array('parent' => $nodes[$treeid]['parent']?:0);
$nodes[$nodes[$val]['parent']][] = &$nodes[$val];
}
break;
default:
trigger_error("Unknown tree traverse-type: $type", E_USER_WARNING);
}
}
$keystofetch = implode(',',array_filter(array_keys($nodes)));
$messages = imap_fetch_overview($imap,$keystofetch, FT_UID);
foreach($messages as $message){
$ids[$message->uid] = $message->from.':'.$message->subject;
}
$it = new RecursiveTreeIterator(new RecursiveArrayIterator($nodes[0]),
RecursiveTreeIterator::BYPASS_CURRENT,
CachingIterator::TOSTRING_USE_KEY);
foreach($it as $key => $item){
echo "$key".(is_scalar($item)?': '.$item:'').PHP_EOL;
}
这给我们带来了:
|-children
|-0
| |-parent: 0
| |-id: 35
| |-message: Friend Purple Acc2 <purple2@example.com>:A bigger message thread
| |-treeid: 1
| \-0
| |-parent: 1
| |-id: 7
| |-message: Friend White <white@example.com>:Re: A bigger message thread
| |-treeid: 2
| \-0
| |-parent: 2
| |-id: 11
| |-message: Friend Grey <grey@example.com>Re: A bigger message thread
| |-treeid: 3
| \-0
| |-parent: 3
| |-id: 39
| |-message: Friend Purple Acc2 <purple2@example.com>:Re: A bigger message thread
| |-treeid: 4
| \-0
| |-parent: 4
| |-id: 40
| |-message: Friend Pink <pink@example.com>:Re: A bigger message thread
| |-treeid: 5
| \-0
| |-parent: 5
| |-id: 38
| |-message: Friend Yellow <yellow@example.com>:Re: A bigger message thread
| |-treeid: 6
| \-0
| |-parent: 6
| |-id: 12
| |-message: Friend Pink <pink@example.com>:Re: A bigger message thread
| |-treeid: 7
| \-0
| |-parent: 7
| |-id: 25
| |-message: Friend White <white@example.com>:Re: A bigger message thread
| |-treeid: 8
| \-0
| |-parent: 8
| |-id: 19
| |-message: Friend Black <black@example.com>:Re: A bigger message thread
| |-treeid: 9
| \-0
| |-parent: 9
| |-id: 23
| |-message: Friend Black <black@example.com>:Re: A bigger message thread
| |-treeid: 10
| \-0
| |-parent: 10
| |-id: 30
| |-message: Friend Yellow <yellow@example.com>:Re: A bigger message thread
| |-treeid: 11
| \-0
| |-parent: 11
| |-id: 2
| |-message: Friend Yellow <yellow@example.com>:Re: A bigger message thread
| |-treeid: 12
| |-0
| | |-parent: 12
| | |-id: 20
| | |-message: Me <me@example.com>:Re: A bigger message thread
| | |-treeid: 13
| | \-0
| | |-parent: 13
| | |-id: 1
| | |-message: Fiend Silver <silver@example.com>:Re: A bigger message thread
| | |-treeid: 14
| | \-0
| | |-parent: 14
| | |-id: 41
| | |-message: Fiend Silver <silver@example.com>:Re: A bigger message thread
| | |-treeid: 15
| | \-0
| | |-parent: 15
| | |-id: 27
| | |-message: Friend Grey <grey@example.com>Re: A bigger message thread
| | |-treeid: 16
| | \-0
| | |-parent: 16
| | |-id: 17
| | |-message: Friend Magenta <magenta@example.com>:Re: A bigger message thread
| | |-treeid: 17
| | |-0
| | | |-parent: 17
| | | |-id: 31
| | | |-message: Friend Purple <purple@example.com>:Re: A bigger message thread
| | | |-treeid: 18
| | | \-0
| | | |-parent: 18
| | | |-id: 4
| | | |-message: Friend Black <black@example.com>:Re: A bigger message thread
| | | |-treeid: 19
| | | \-0
| | | |-parent: 19
| | | |-id: 37
| | | |-message: Friend Black <black@example.com>:Re: A bigger message thread
| | | |-treeid: 20
| | | \-0
| | | |-parent: 20
| | | |-id: 24
| | | |-message: Friend Purple Acc2 <purple2@example.com>:Re: A bigger message thread
| | | |-treeid: 21
| | | \-0
| | | |-parent: 21
| | | |-id: 13
| | | |-message: Friend White <white@example.com>:Re: A bigger message thread
| | | \-treeid: 22
| | \-1
| | |-parent: 17
| | |-id: 15
| | |-message: Friend Grey <grey@example.com>Re: A bigger message thread
| | |-treeid: 23
| | \-0
| | |-parent: 23
| | |-id: 18
| | |-message: Friend Magenta <magenta@example.com>:Re: A bigger message thread
| | |-treeid: 24
| | \-0
| | |-parent: 24
| | |-id: 45
| | |-message: Friend Black <black@example.com>:Re: A bigger message thread
| | \-treeid: 25
| \-1
| |-parent: 12
| |-id: 46
| |-message: Friend Yellow <yellow@example.com>:Re: A bigger message thread
| |-treeid: 26
| \-0
| |-parent: 26
| |-id: 29
| |-message: Fiend Silver <silver@example.com>:Re: A bigger message thread
| |-treeid: 27
| \-0
| |-parent: 27
| |-id: 26
| |-message: Friend Magenta <magenta@example.com>:Re: A bigger message thread
| |-treeid: 28
| |-0
| | |-parent: 28
| | |-id: 34
| | |-message: Friend Grey <grey@example.com>Re: A bigger message thread
| | \-treeid: 29
| |-1
| | |-parent: 28
| | |-id: 33
| | |-message: Friend Yellow <yellow@example.com>:Re: A bigger message thread
| | |-treeid: 30
| | \-0
| | |-parent: 30
| | |-id: 36
| | |-message: Friend White <white@example.com>:Re: A bigger message thread
| | |-treeid: 31
| | |-0
| | | |-parent: 31
| | | |-id: 10
| | | |-message: Friend White <white@example.com>:Re: A bigger message thread
| | | \-treeid: 32
| | \-1
| | |-parent: 31
| | |-id: 48
| | |-message: Friend Pink <pink@example.com>:Re: A bigger message thread
| | \-treeid: 33
| \-2
| |-parent: 28
| |-id: 47
| |-message: Friend Purple <purple@example.com>:Re: A bigger message thread
| |-treeid: 34
| \-0
| |-parent: 34
| |-id: 5
| |-message: Friend White <white@example.com>:Re: A bigger message thread
| |-treeid: 35
| \-0
| |-parent: 35
| |-id: 3
| |-message: Friend Purple <purple@example.com>:Re: A bigger message thread
| |-treeid: 36
| \-0
| |-parent: 36
| |-id: 21
| |-message: Friend Yellow <yellow@example.com>:Re: A bigger message thread
| |-treeid: 37
| \-0
| |-parent: 37
| |-id: 8
| |-message: Friend Purple <purple@example.com>:Re: A bigger message thread
| |-treeid: 38
| \-0
| |-parent: 38
| |-id: 43
| |-message: Friend White <white@example.com>:Re: A bigger message thread
| |-treeid: 39
| \-0
| |-parent: 39
| |-id: 28
| |-message: Friend Purple <purple@example.com>:Re: A bigger message thread
| |-treeid: 40
| \-0
| |-parent: 40
| |-id: 42
| |-message: Friend Brown <brown@example.com>:Re: A bigger message thread
| |-treeid: 41
| \-0
| |-parent: 41
| |-id: 22
| |-message: Friend Purple <purple@example.com>:Re: A bigger message thread
| \-treeid: 42
|-1
| |-parent: 0
| |-id: 9
| |-message: Friend Blue <blue@example.com>:RE: A bigger message thread
| \-treeid: 43
|-2
| \-parent: 0
|-3
| |-parent: 44
| |-id: 49
| |-message: Some Subcription <foo@example.com>:Newsletter
| \-treeid: 45
|-4
| |-parent: 44
| |-id: 50
| |-message: Some Subcription <foo@example.com>:Newsletter
| \-treeid: 46
\-5
|-parent: 0
|-id: 32
|-message: Friend Red <red@example.com>:A second mainthread
|-treeid: 47
\-0
|-parent: 47
|-id: 16
|-message: Friend Black <black@example.com>:Re: A second mainthread
|-treeid: 48
\-0
|-parent: 48
|-id: 14
|-message: Friend Red <red@example.com>:Re: A second mainthread
|-treeid: 49
\-0
|-parent: 49
|-id: 6
|-message: Friend White <white@example.com>:Re: A second mainthread
|-treeid: 50
\-0
|-parent: 50
|-id: 44
|-message: Fiend Silver <silver@example.com>:Re: A second mainthread
\-treeid: 51
需要注意的几点:
- 此脚本的第一个版本错误地将分支添加到节点的第一个子节点而不是实际的节点本身,现在通过同时存储其父节点来解决这个问题。
imap_thread
并不完美:我们将id = 9
视为孤立节点,尽管它似乎应该在某个地方作为第一个线程。但是,由于头部没有提到这一点,谷歌应用程序决定将其作为自己的节点。
- 第三个(key = 2)条目是一个“返回根”的方法,因为
N.num.N.branch,N.next
方法显然没有其他返回根的方法。这是/return to root $ nodes [$ treeid] = & $ nodes [0];
一小部分。在确定所有其他节点之后,您可以/应该过滤掉它,但是您需要它来首先构建数组。
仅获取开始新线程的节点(消息上的第N次回复,N> 1):
$threads = imap_thread($imap, SE_UID);
$branchestarts = array();
foreach($threads as $key => $value){
list($num,$type) = explode('.',$key);
if (
$type=='num'
&& $value == 0
&& isset($threads[$num.'.next'])
&& isset($threads[$threads[$num.'.next'].'.num'])
){
$branchestarts[] = $threads[$threads[$num.'.next'].'.num'];
} else if(
$type=='branch'
&& $value != 0
&& isset($threads[$value.'.num'])
&& $threads[$value.'.num'] != 0
){
$branchestarts[] = $threads[$value.'.num'];
}
}
echo json_encode($branchestarts);
这给了我们:
[35,15,46,33,48,47,9,49,50,32]
实际上,35、49、50和32都是线程的开头,imap服务器也将9识别为线程的开头,其余的则是第二个或更多回复,开始他们自己的分支。
现在,你确实可以将分支拆分为单独的对话,但正如你所看到的,这些通常只有1或2个回复,较长的线程往往不太常见。
要查看这些“分支”的情况:
$branches = array();
$currenttree = null;
foreach($threads as $key => $value){
list($num,$type) = explode('.',$key);
switch($type){
case 'num':
break;
case 'next':
if(is_null($currenttree)) $currenttree = &$branches[$threads[$value.'.num']];
if($value && isset($threads[$value.'.num'])) $currenttree[] = $threads[$value.'.num'];
break;
case 'branch':
unset($currenttree);
if($value && $threads[$value.'.num']){
$branches[$threads[$value.'.num']] = array($threads[$value.'.num']);
$currenttree =& $branches[$threads[$value.'.num']];
}
}
}
echo json_encode($branches, JSON_PRETTY_PRINT);
这给你根和枝及其回复:
{
"35": [
35,
7,
11,
39,
40,
38,
12,
25,
19,
23,
30,
2,
20,
1,
41,
27,
17,
31,
4,
37,
24,
13
],
"15": [
15,
18,
45
],
"46": [
46,
29,
26,
34
],
"33": [
33,
36,
10
],
"48": [
48
],
"47": [
47,
5,
3,
21,
8,
43,
28,
42,
22
],
"9": [
9
],
"49": [
49
],
"50": [
50
],
"32": [
32,
16,
14,
6,
44
]
}
通过一些微小的修改,我们可以将消息放入其中:
$branches = array();
$currenttree = null;
$messages = array();
foreach($threads as $key => $value){
list($num,$type) = explode('.',$key);
switch($type){
case 'num':
break;
case 'next':
if(is_null($currenttree)) $currenttree = &$branches[$threads[$value.'.num']];
if($value && isset($threads[$value.'.num'])) $currenttree[] = &$messages[$threads[$value.'.num']];
break;
case 'branch':
unset($currenttree);
if($value && $threads[$value.'.num']){
$branches[$threads[$value.'.num']] = array(&$messages[$threads[$value.'.num']]);
$currenttree =& $branches[$threads[$value.'.num']];
} else {
$currenttree = null;
}
}
}
$keystofetch = implode(',',array_filter(array_keys($messages)));
foreach(imap_fetch_overview($imap,$keystofetch,FT_UID) as $message){
$messages[$message->uid] = $message;
}
echo json_encode($branches);
另一个选择是按照日期时间值对它们进行排序,这对于具有较少/可忽略分支的对话来说还可以接受,可能会使您计划的大部分代码正常工作。
两者的组合将是“移动分支”,按系列跟随线程,因此:
1 2013-06-01
2 2013-06-02
3 2013-06-03
4 2013-06-03
5 2013-06-04
成为一个
1,2,3,4,5
的序列,但对
3
的回复会导致重排:
1 2013-06-01
4 2013-06-03
5 2013-06-04
2 2013-06-02
3 2013-06-03
6 2013-06-05
将其变成序列
1,4,5,2,3,6
,这将使其保持逻辑上的连贯对话,始终以最后回复为最后一个线索/分支。
$root
是什么?你想通过嵌套的foreach
循环实现什么目标?看起来你应该遍历$emails
,但需要更多的澄清来说明你想做什么。 - Frank Riccobonoimap_thread
函数在 PHP 手册中的一个评论。http://www.php.net/manual/en/function.imap-thread.php#104056 我认为这正是你想要做的事情。 - Frank Riccobono(1 2 3)
还包括(1 2 (3 4 (5 6) 7) 8 9)
? - Wrikken