用PHP从多维数组(IMAP)创建消息线程的多维数组

5

我的问题如下:

如果您往下看,您会看到一个数据结构,其中包含消息id,然后是最终的数据结构,包含应从imap_fetch_overview聚合的消息详细信息。消息id来自imap_thread。问题在于它没有将电子邮件详细信息放在消息id所在的位置。

这是我的数据结构:

[5] => Array
    (
        [0] => 5
        [1] => 9
    )

[10] => Array
    (
        [0] => 10
        [1] => 11
    )

我希望你能够提供以下内容:

[5] => Array
    (
        [0] => messageDetails for id 5
        [1] => messageDetails for id 9
    )

[10] => Array
    (
        [0] => messageDetails for id 10
        [1] => messageDetails for id 11
    )

这是我目前的代码:

这是我目前的代码:

$emails = imap_fetch_overview($imap, implode(',',$ids));

// root is the array index position of the threads message, such as 5 or 10
foreach($threads as $root => $messages){

    // id is the id being given to us from `imap_thread`
    foreach($message as $key => $id){

      foreach($emails as $index => $email){

         if($id === $email->msgno){
             $threads[$root][$key] = $email;
             break;
          }
      }
    }
 }

这是来自其中一封电子邮件的打印输出:
    [0] => stdClass Object
    (
        [subject] => Cloud Storage Dump
        [from] => Josh Doe
        [to] => jondoe@domain.com
        [date] => Mon, 21 Jan 2013 23:18:00 -0500
        [message_id] => <50FE12F8.9050506@domain.com>
        [size] => 2559
        [uid] => 5
        [msgno] => 5
        [recent] => 0
        [flagged] => 0
        [answered] => 1
        [deleted] => 0
        [seen] => 0
        [draft] => 0
        [udate] => 1358828308
    )

如果你注意到,msgno是5,对应于$id,因此从技术上讲,数据应该填充到最终的数据结构中。
此外,这似乎是一种低效的处理方式。
如果需要任何额外的澄清,请告诉我。
更新代码
这段代码是我在php api上找到的代码和我自己修复的一些问题的组合。我认为有问题的仍然是$root。
$addedEmails = array();
$thread = imap_thread($imap);
foreach ($thread as $i => $messageId) { 
    list($sequence, $type) = explode('.', $i); 
    //if type is not num or messageId is 0 or (start of a new thread and no next) or is already set 
   if($type != 'num' || $messageId == 0 || ($root == 0 && $thread[$sequence.'.next'] == 0) || isset($rootValues[$messageId])) { 
    //ignore it 
    continue; 
} 

if(in_array($messageId, $addedEmails)){
    continue;
}
array_push($addedEmails,$messageId);

//if this is the start of a new thread 
if($root == 0) { 
    //set root 
    $root = $messageId; 
} 

//at this point this will be part of a thread 
//let's remember the root for this email 
$rootValues[$messageId] = $root; 

//if there is no next 
if($thread[$sequence.'.next'] == 0) { 
    //reset root 
    $root = 0; 
    } 
  }
$ids=array();
$threads = array();
foreach($rootValues as $id => $root){
    if(!array_key_exists($root,$threads)){
        $threads[$root] = array();
    }
    if(!in_array($id,$threads[$root])){
        $threads[$root][] = $id;
       $ids[]=$id;
    }
 }
 $emails = imap_fetch_overview($imap, implode(',', array_keys($rootValues)));

 $keys = array();
 foreach($emails as $k => $email)
 {
$keys[$email->msgno] = $k;
 }

 $threads = array_map(function($thread) use($emails, $keys)
{
// Iterate emails in these threads
return array_map(function($msgno) use($emails, $keys)
{
    // Swap the msgno with the email details
    return $emails[$keys[$msgno]];

}, $thread);
}, $threads);

$root是什么?你想通过嵌套的foreach循环实现什么目标?看起来你应该遍历$emails,但需要更多的澄清来说明你想做什么。 - Frank Riccobono
你可能想看一下 imap_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
@Wrikken,我对那种情况一无所知。你能帮忙吗? - somejkuser
@jkushner:我尽力在那个问题周围讲解了一些/编写了一些代码。然而,分支意味着生成的数组往往看起来与您现在使用的数组非常不同,所以我不知道它是否符合您的要求。你的情况可能有所不同,但就是这样。 - Wrikken
@Wrikken 我需要一点时间来消化这个。现在我理解了你对分支的关注,看起来这是我需要的解决方案。 - somejkuser
4个回答

4
请记住,在php中,无论使用哪个函数,最终都会被转换为某种形式的循环。 然而,在PHP 5.5和5.3/5.4中,您可以采取一些步骤使其更加高效。
PHP 5.3/5.4方法
最有效的方法是将该函数拆分为2个单独的步骤。 第一步,您需要生成电子邮件列表键的映射。
$keys = array();
foreach($emails as $k => $email)
{
    $keys[$email->msgno] = $k;
}

在第二步中,您需要遍历多维数组$threads中的所有值,并将它们替换为电子邮件详细信息:
// Iterate threads
$threads = array_map(function($thread) use($emails, $keys)
{
    // Iterate emails in these threads
    return array_map(function($msgno) use($emails, $keys)
    {
        // Swap the msgno with the email details
        return $emails[$keys[$msgno]];

    }, $thread);

}, $threads);

概念验证:http://pastebin.com/rp5QFN4J

匿名函数中use关键字的说明:

为了使用父作用域中定义的变量,可以使用use()关键字将变量从父作用域导入闭包作用域。虽然它是在PHP 5.3中引入的,但官方PHP手册尚未对其进行记录。这里只有php维基上的草案文件https://wiki.php.net/rfc/closures#userland_perspective

PHP 5.5

此版本的新功能之一是可以使用生成器,其内存占用更小,因此更有效率。

生成器中yield关键字的说明:

生成器函数的核心是yield关键字。在最简单的形式下,yield语句看起来很像一个return语句,但不同的是,yield不会停止函数的执行并返回,而是向正在循环生成器的代码提供一个值,并暂停生成器函数的执行。

第一步:

function genetateKeyMap($emails)
{
    foreach($emails as $k => $email)
    {
        // Yielding key => value pair to result set
        yield $email->msgno => $k;
    }
};
$keys = iterator_to_array(genetateKeyMap($emails));

第二步:

function updateThreads($emails, $threads, $keys)
{
    foreach($threads as $thread)
    {
        $array = array();

        // Create a set of detailed emails
        foreach($thread as $msgno)
        {
            $array[] = $emails[$keys[$msgno]];
        }

        // Yielding array to result set
        yield $array;
    }
};
$threads = iterator_to_array(updateThreads($emails, $threads, $keys));

关于生成器返回的值:

生成器返回一个SPL Iterator实例对象,因此需要使用iterator_to_array()将其转换为你的代码期望的完全相同的数组结构。虽然您不需要这样做,但它需要在生成器函数后更新您的代码,这可能会更加高效。

概念证明:http://pastebin.com/9Z4pftBH

性能测试:

我生成了一个包含7000个线程,每个线程有5个消息的列表,并测试了每种方法的性能(取5次测试的平均值):

                   Takes:       Memory used:
                   ----------------------------
3x foreach():      2.8s              5.2 MB
PHP 5.3/5.4 way    0.061s            2.7 MB
PHP 5.5 way        0.036s            2.7 MB

尽管您的电脑/服务器上的结果可能会有所不同,但总体来说,使用2步方法比使用3个foreach循环快约45-77倍。
测试脚本:http://pastebin.com/M40hf0x7

我不确定。最好您拿其中一个您期望存在的电子邮件(但实际上不存在)并查看它是否在imap_thread()中返回。如果是,那就意味着您有一个错误。 - WooDzu
太奇怪了。我刚刚登录想给你写信,告诉你我再仔细想了一下,发现你的答案是最好的。我被另一个答案震惊了,我知道把那个标记为最佳答案是个错误。我会尝试看看能否更改它。如果不能,我很抱歉。希望这不会阻止你回答我的更多问题。 - somejkuser
我已经采纳了你的答案。不幸的是,悬赏已经被提供了。我认为他应该得到这个奖励,因为他触及到了你们中没有人能够达到的答案。另一方面,你的答案是最好的。所以最终一切都解决了。 - somejkuser
嗯,yield是一个很好的话题和答案,但这取决于获取资源以产生的开销。顺便说一下:当获取更多的imap消息,并且您 需要 它们全部时,通常更有效的方法是一次性获取 所有 而不是产生。然而,如果您只需要子集、内存有限或获取一个或所有项目的开销差异可以忽略不计,则 yield 是 _非常棒的_。我想你想要赏金在这里,所以我会把它添加回问题并在让我能够这样做的时候在这里授予它 ;) - Wrikken
你知道,最棒的事情是人们来到这里分享他们的知识和经验,并且他们并没有因此得到报酬,更重要的是他们不期望被奖励或者赞扬,至少大部分人都是这样。我很高兴我能够为你提供帮助,也许对于未来寻找相同或类似问题答案的其他人也有所帮助。实际上,这些点总是能让你更加快乐,但它们无法替代你在工作中赚取的钱 =] - WooDzu
显示剩余8条评论

2
当您使用print_r打印$emails数组时,您会得到什么结构?也许下面的代码可以做到这一点?
 $threads[$root][$key] = $emails[$key];

你能按照这个用户的建议提供一下 print_r($emails) 的返回结果吗? - Frank Riccobono
如果您尝试使用print_r($emails),您会得到什么? - georgec20001
将 ($id === $email->msgno) 改为 ($id == $email['msgno'])。 - georgec20001

0

我现在没有访问PHP的权限来进行测试,但我相信你想要做的是类似于以下内容:

foreach($emails as $email) {
    foreach($threads as $root => $messages) {
        foreach($messages as $index =>$message_id){
            if($message_id == $email->msgno){
                 $threads[$root][$index] = $email;
            }
        }
    }
}

话虽如此,即使这样可以工作,也可能有比三个嵌套循环更有效的方法来处理。您需要以这种格式存储输出的原因是什么?


我认识到有更好的方法,只是不知道是什么。我想我在我的描述中已经说明了我正在寻找最优化的版本。 - somejkuser

0

一个带有分支的实现(比单线程array('5' => array(5,7,8))更复杂),但除非我只和一个人交流,否则对我个人来说,线程总是倾向于分支,所以我必须应对额外的复杂性。

<?php 
$threads = imap_thread($imap, SE_UID);
/*
 * threads returns entries as follows:
 * <id>.num = <messageid>
 * <id>.next = <messageid of first reply to <id>>,  0 = no replies
 * <id>.branch = <messageid of nth. reply to <parent of id>>, 0 = no more branches
 * Keep in mind: _every_ message 'starts' a branch, but that may be empty.
 */
$nodes = array( 0 => array( 'children' => array()));
$ids = array();
foreach ($threads as $key => $val) {
    list($treeid,$type) = explode('.',$key);
    switch($type){
        case 'num':
            //the actual message number of this tree node
            //store id for retrieval later:
            $ids[$val] = null;
            if($val==0){
                //return to root
                $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':
            // 0 means no next message, anything else is a reply
            if (0!=$val) {
                if(!isset($nodes[$val])) $nodes[$val] = array('parent' => $treeid);
                $nodes[$treeid][] = &$nodes[$val];
            }
            break;
        case 'branch':
            //0 means end of branch, a number means continue as sibling \
            //so we need to know the parent
            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);
    }
}
//the great thing is we can get all our ID's at once:
$keystofetch = implode(',',array_filter(array_keys($nodes)));
$messages = imap_fetch_overview($imap,$keystofetch, FT_UID);
foreach($messages as $message){
    // you can of course store the _whole_ message in this thread like:
    // $nodes[$message->uid]['message'] = get_object_vars($message);
    // and do what you like with $tree[0]['children'] (be it a resursive array iterator,
    // or a  resursive function, your pick.
    // However, for this example we are going to only set message to a string of p.o.c 
    // (which is also nicer for our treeiterator)
    $ids[$message->uid] = $message->from.':'.$message->subject;
}
//let's show the result:
$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 #1
| \-treeid: 45
|-4
| |-parent: 44
| |-id: 50
| |-message: Some Subcription <foo@example.com>:Newsletter #2
| \-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'                     // an id
        && $value == 0                   // which is actually root
        && isset($threads[$num.'.next']) // then check for next
        && isset($threads[$threads[$num.'.next'].'.num'])
    ){
        $branchestarts[] = $threads[$threads[$num.'.next'].'.num'];
    } else if(
        $type=='branch'                   // branch movement
        && $value != 0                    // not back
        && isset($threads[$value.'.num']) // sanity: target exists
        && $threads[$value.'.num'] != 0   // and is not a return to root
    ){
        $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':
            //nothing
            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':
            //nothing
            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);//won't show it's output, this answer is to large as it is ;)

另一个选择是按照日期时间值对它们进行排序,这对于具有较少/可忽略分支的对话来说还可以接受,可能会使您计划的大部分代码正常工作。
两者的组合将是“移动分支”,按系列跟随线程,因此:
 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,这将使其保持逻辑上的连贯对话,始终以最后回复为最后一个线索/分支。

通过这个解决方案,我不仅需要获取根节点,还需要扫描子节点并查找新的分支线程。我希望最终得到一个数组,其中包含根节点及其相应的子节点,然后我可以将分支的电子邮件与其自己的子节点放在与根节点相同的级别上进行可视化。这样说您是否明白?我可以尝试更好地解释一下。 - somejkuser
嗯,我更喜欢看到我的电子邮件以线程方式排列,但我明白在这个时代,由于使用热门的Hotmail和Gmail而不是实际客户端,这在HTML上下文中可能变得不受欢迎。我会进行一些编辑,找到根节点相对简单。 - Wrikken
此外,我在数据库中存储了消息的parent_id。根节点的parent id为0,子节点将全部具有其父节点的根节点id。然后按时间排序,以最新时间组织它。由于分支,对我来说复杂度变得非常困难,因为我需要遍历树,找到分支,将分支根插入数据库并设置父级为0,遍历其子项并插入分支根的id。如果我们能够想出一种方法将数据库逻辑包含在内,我可以思考一下是否还有什么问题。 - somejkuser
1
好的,最后一点汁加入消息中...希望你喜欢,因为之后我又要离开一天了 :P - Wrikken
1
非常感谢您的帮助。现在我对电子邮件有了更好的理解。您的协助也帮助我成长为一名工程师。非常感谢。 - somejkuser
显示剩余17条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接