[horde] PHP7 : Memory eater bug? -> infinite recursion -> solution proposed

Torben Dannhauer torben at dannhauer.info
Fri Feb 17 22:15:25 UTC 2017


Zitat von Torben Dannhauer <torben at dannhauer.info>:

> Zitat von Michael J Rubinsky <mrubinsk at horde.org>:
>
>> Quoting Torben Dannhauer <torben at dannhauer.info>:
>>
>>> Zitat von Michael J Rubinsky <mrubinsk at horde.org>:
>>>
>>>> Quoting Torben Dannhauer <torben at dannhauer.info>:
>>>>
>>>>> Zitat von Michael J Rubinsky <mrubinsk at horde.org>:
>>>>>
>>>>>> Quoting Torben Dannhauer <torben at dannhauer.info>:
>>>>>>
>>>>>>> Zitat von Torben Dannhauer <torben at dannhauer.info>:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Yesterday I discovered a lot of errors thrown by PHP7 due to my memory
>>>>>>>> limit.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> I get lots of errors like this:
>>>>>>>>
>>>>>>>> <snip>
>>>>>>>>
>>>>>>>> [13-Feb-2017 09:57:35 Europe/Berlin] PHP Fatal error:   
>>>>>>>> Allowed memory size
>>>>>>>> of 1073741824 bytes exhausted (tried to allocate 20480 bytes) in
>>>>>>>> /var/www/torben/web/ssl-dannhauer.de/horde/mnemo/lib/Mnemo.php on  
>>>>>>>> line 537
>>>>>>>>
>>>>>>>> [13-Feb-2017 09:57:35 Europe/Berlin] PHP Fatal error:   
>>>>>>>> Allowed memory size
>>>>>>>> of 1073741824 bytes exhausted (tried to allocate 20480 bytes) in
>>>>>>>> /usr/share/php/Horde/ErrorHandler.php on line 193
>>>>>>>>
>>>>>>>> [13-Feb-2017 09:58:08 Europe/Berlin] PHP Fatal error:   
>>>>>>>> Allowed memory size
>>>>>>>> of 1073741824 bytes exhausted (tried to allocate 20480 bytes) in
>>>>>>>> /var/www/torben/web/ssl-dannhauer.de/horde/mnemo/lib/Mnemo.php on  
>>>>>>>> line 537
>>>>>>>>
>>>>>>>> [13-Feb-2017 09:58:08 Europe/Berlin] PHP Fatal error:   
>>>>>>>> Allowed memory size
>>>>>>>> of 1073741824 bytes exhausted (tried to allocate 20480 bytes) in
>>>>>>>> /usr/share/php/Horde/ErrorHandler.php on line 193
>>>>>>>>
>>>>>>>> <snap>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> It doesn't matter whether my limit is configured as 512M, 2G  
>>>>>>>> or 3G. Anyway,
>>>>>>>> a limit exceed in that order of memory is very likely to be a bug.
>>>>>>>>
>>>>>>>> Unfortunatly I do not have a clue how to start debugging  
>>>>>>>> here. The System
>>>>>>>> itself shows of course only the processes, not the memory  
>>>>>>>> consumption of
>>>>>>>> every running script.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Any hints whjere to start?
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Many thanks,
>>>>>>>>
>>>>>>>> Torben
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> I'm getting closer to the problem.
>>>>>>>
>>>>>>> I installed xdebug to dive deeper into the issue and  
>>>>>>> discovered that the error does not longer occur as long als  
>>>>>>> xdebug is loaded into PHP.
>>>>>>> Screening the tons of logs produced by xdebug, I sawthat  
>>>>>>> xedebug cancels the execution due to the max_nesting level. So  
>>>>>>> the error still DOES occur, but is catched by xdebug and  
>>>>>>> announced in the loggs with different message.
>>>>>>> Here is the full log, it indicates an endless recursion in  
>>>>>>> mnemo - whit fits perfect to the picture of this issue:
>>>>>>>
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP Fatal error:  Maximum  
>>>>>>> function nesting level of '256' reached, aborting! in  
>>>>>>> /usr/share/php/Horde/ErrorHandler.php on line 193
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP Stack trace:
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   1. {main}()  
>>>>>>> <webroot>/horde/rpc.php:0
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   2.  
>>>>>>> Horde_Rpc_ActiveSync->getResponse() <webroot>/horde/rpc.php:160
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   3.  
>>>>>>> Horde_ActiveSync->handleRequest()  
>>>>>>> /usr/share/php/Horde/Rpc/ActiveSync.php:143
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   4.  
>>>>>>> Horde_ActiveSync_Request_Base->handle()  
>>>>>>> /usr/share/php/Horde/ActiveSync.php:834
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   5.  
>>>>>>> Horde_ActiveSync_Request_Ping->_handle()  
>>>>>>> /usr/share/php/Horde/ActiveSync/Request/Base.php:253
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   6.  
>>>>>>> Horde_ActiveSync_Collections->pollForChanges()  
>>>>>>> /usr/share/php/Horde/ActiveSync/Request/Ping.php:222
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   7.  
>>>>>>> Horde_ActiveSync_Collections->getCollectionChangeCount()  
>>>>>>> /usr/share/php/Horde/ActiveSync/Collections.php:1222
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   8.  
>>>>>>> Horde_ActiveSync_Collections->getCollectionChanges()  
>>>>>>> /usr/share/php/Horde/ActiveSync/Collections.php:1417
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP   9.  
>>>>>>> Horde_ActiveSync_State_Base->getChanges()  
>>>>>>> /usr/share/php/Horde/ActiveSync/Collections.php:1401
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  10.  
>>>>>>> Horde_Core_ActiveSync_Driver->getServerChanges()  
>>>>>>> /usr/share/php/Horde/ActiveSync/State/Base.php:437
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  11.  
>>>>>>> Horde_Core_ActiveSync_Connector->getChanges()  
>>>>>>> /usr/share/php/Horde/Core/ActiveSync/Driver.php:1112
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  12.  
>>>>>>> Horde_Registry_Caller->getChangesByModSeq()  
>>>>>>> /usr/share/php/Horde/Core/ActiveSync/Connector.php:1098
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  13.  
>>>>>>> Horde_Registry_Caller->__call()  
>>>>>>> /usr/share/php/Horde/Core/ActiveSync/Connector.php:1098
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  14.  
>>>>>>> Horde_Registry->call()  
>>>>>>> /usr/share/php/Horde/Registry/Caller.php:41
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  15.  
>>>>>>> Horde_Registry->callByPackage()  
>>>>>>> /usr/share/php/Horde/Registry.php:1088
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  16.  
>>>>>>> Mnemo_Api->getChangesByModSeq()  
>>>>>>> /usr/share/php/Horde/Registry.php:1131
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  17.  
>>>>>>> Mnemo_Api->getChanges() <webroot>/horde/mnemo/lib/Api.php:135
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  18.  
>>>>>>> Mnemo_Api->listBy() <webroot>/horde/mnemo/lib/Api.php:117
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP  19.  
>>>>>>> Mnemo_Api->listBy() <webroot>/horde/mnemo/lib/Api.php:158
>>>>>>> [.... and so on...]
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP 252.  
>>>>>>> Mnemo_Api->listBy() <webroot>/horde/mnemo/lib/Api.php:158
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP 253.  
>>>>>>> Mnemo_Api->listBy() <webroot>/horde/mnemo/lib/Api.php:158
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP 254.  
>>>>>>> Mnemo::getSyncNotepads() <webroot>/horde/mnemo/lib/Api.php:155
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP 255.  
>>>>>>> Horde_Prefs->getValue() <webroot>/horde/mnemo/lib/Mnemo.php:538
>>>>>>> [16-Feb-2017 13:20:50 Europe/Berlin] PHP 256.  
>>>>>>> Horde_Prefs->_getScope() /usr/share/php/Horde/Prefs.php:289
>>>>>>>
>>>>>>> I'm happy to get any hint what might be the reason. I assume  
>>>>>>> something to do with PHP7 ;)
>>>>>>
>>>>>> Can you see what Mnemo::getSyncNotepads(); returns? Easiest way  
>>>>>> would be to use admin->phpshell from within horde, be sure to  
>>>>>> choose the Mnemo scope from the drop down menu.
>>>>>>
>>>>>
>>>>> Oh, have never thought to use the Horde build in shell to debug :)
>>>>> Anyway, I enhanced the loggin in the file since not every  
>>>>> access/client triogfgers the issue, it happens only occassionally.
>>>>>
>>>>> The function  listBy($action, $timestamp, $notepad = null, $end  
>>>>> = null, $isModSeq = false)
>>>>> if called with the parameters action:add timestamp:50855  
>>>>> notepad: end:51055 isModSeq:1
>>>>> in the recursive loop. The queried array is then.
>>>>> Array
>>>>> (
>>>>> [0] =>
>>>>> )
>>>>>
>>>>> What is the intented logic if an empty array is returned?
>>>>
>>>> First, I'm assuming that the above parameters were supplied to  
>>>> the function, when it's called from line 158?
>>>
>>> Yes, I extenced the function to this:
>>> public function listBy($action, $timestamp, $notepad = null, $end  
>>> = null, $isModSeq = false)
>>>   {
>>> Horde::log('action:'.$action.' timestamp:'.$timestamp.'  
>>> notepad:'.$notepad.' end:'.$end.' isModSeq:'.$isModSeq, 'ERR');
>>>       /* Make sure we have a valid notepad. */
>>>       if (empty($notepad)) {
>>>           $notepads = Mnemo::getSyncNotepads();
>>> Horde::log('notepads: '.print_r($notepads, true) ,'ERR');
>>>           $results = array();
>>>           foreach ($notepads as $notepad) {
>>>               $results = array_merge($results,  
>>> $this->listBy($action, $timestamp, $notepad, $end, $isModSeq));
>>>           }
>>>           return $results;
>>>       }
>>>
>>>       $filter = array(array('op' => '=', 'field' => 'action',  
>>> 'value' => $action));
>>>       if (!empty($end) && !$isModSeq) {
>>>           $filter[] = array('op' => '<', 'field' => 'ts', 'value' => $end);
>>>       }
>>>       $history = $GLOBALS['injector']->getInstance('Horde_History');
>>>       if (!$isModSeq) {
>>>           $histories = $history->getByTimestamp('>', $timestamp,  
>>> $filter, 'mnemo:' . $notepad);
>>>       } else {
>>>           $histories = $history->getByModSeq($timestamp, $end,  
>>> $filter, 'mnemo:' . $notepad);
>>>       }
>>>
>>>       // Strip leading mnemo:username:.
>>>       return preg_replace('/^([^:]*:){2}/', '', array_keys($histories));
>>>   }
>>>
>>> The corresponding log in the endless loop is:
>>> <snip>
>>> 2017-02-17T13:38:08+01:00 ERR: HORDE [mnemo] action:add  
>>> timestamp:50855 notepad: end:51055 isModSeq:1 [pid 29265 on line  
>>> 153 of "<webroot>/horde/mnemo/lib/Api.php"]
>>> 2017-02-17T13:38:08+01:00 ERR: HORDE [mnemo] notepads: Array
>>> (
>>>   [0] =>
>>> )
>>> [pid 29265 on line 157 of "<webroot>/horde/mnemo/lib/Api.php"]
>>> 2017-02-17T13:38:08+01:00 ERR: HORDE [mnemo] action:add  
>>> timestamp:50855 notepad: end:51055 isModSeq:1 [pid 29265 on line  
>>> 153 of "<webroot>/horde/mnemo/lib/Api.php"]
>>> 2017-02-17T13:38:08+01:00 ERR: HORDE [mnemo] notepads: Array
>>> (
>>>   [0] =>
>>> )
>>> [pid 29265 on line 157 of "<webroot>/horde/mnemo/lib/Api.php"]
>>> 2017-02-17T13:38:08+01:00 ERR: HORDE [mnemo] action:add  
>>> timestamp:50855 notepad: end:51055 isModSeq:1 [pid 29265 on line  
>>> 153 of "<webroot>/horde/mnemo/lib/Api.php"]
>>> 2017-02-17T13:38:08+01:00 ERR: HORDE [mnemo] notepads: Array
>>> (
>>>   [0] =>
>>> )
>>> [pid 29265 on line 157 of "<webroot>/horde/mnemo/lib/Api.php"]
>>> <snap>
>>>
>>>
>>>>
>>>> An empty array would simply mean that there were no matches for  
>>>> that type of change. I.e., no new notes added, or changed etc...  
>>>> However, that's not technically an empty array, it's an array  
>>>> with an empty first element. That really shouldn't happen there.  
>>>> Even though that's not expected, if that gets sent back up to  
>>>> ActiveSync, it would probaly lead to some "item not found"  
>>>> message in the log, at least that's what it looks like should  
>>>> happen after a quick glance at the code.
>>>>
>>>> The bigger question is why is there no notepad being passed in  
>>>> the $notepad parameter? THAT is the cause of the loop:
>>>
>>> For sure. It seems (several users, the loog is flooded by the  
>>> debug messages and I have to seperate it be the PID), that it  
>>> directly called with an empty $notepad. So it seems _not_ to  
>>> "become empty" during the recursive iteration.
>>>
>>> The stack trace of the erroneous situation is:
>>>
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP Stack trace:
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   1. {main}()  
>>> <webroot>/horde/rpc.php:0
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   2.  
>>> Horde_Rpc_ActiveSync->getResponse() <webroot>/horde/rpc.php:160
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   3.  
>>> Horde_ActiveSync->handleRequest()  
>>> /usr/share/php/Horde/Rpc/ActiveSync.php:143
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   4.  
>>> Horde_ActiveSync_Request_Base->handle()  
>>> /usr/share/php/Horde/ActiveSync.php:834
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   5.  
>>> Horde_ActiveSync_Request_Ping->_handle()  
>>> /usr/share/php/Horde/ActiveSync/Request/Base.php:253
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   6.  
>>> Horde_ActiveSync_Collections->pollForChanges()  
>>> /usr/share/php/Horde/ActiveSync/Request/Ping.php:222
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   7.  
>>> Horde_ActiveSync_Collections->getCollectionChangeCount()  
>>> /usr/share/php/Horde/ActiveSync/Collections.php:1222
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   8.  
>>> Horde_ActiveSync_Collections->getCollectionChanges()  
>>> /usr/share/php/Horde/ActiveSync/Collections.php:1417
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP   9.  
>>> Horde_ActiveSync_State_Base->getChanges()  
>>> /usr/share/php/Horde/ActiveSync/Collections.php:1401
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  10.  
>>> Horde_Core_ActiveSync_Driver->getServerChanges()  
>>> /usr/share/php/Horde/ActiveSync/State/Base.php:437
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  11.  
>>> Horde_Core_ActiveSync_Connector->getChanges()  
>>> /usr/share/php/Horde/Core/ActiveSync/Driver.php:1112
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  12.  
>>> Horde_Registry_Caller->getChangesByModSeq()  
>>> /usr/share/php/Horde/Core/ActiveSync/Connector.php:1098
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  13.  
>>> Horde_Registry_Caller->__call()  
>>> /usr/share/php/Horde/Core/ActiveSync/Connector.php:1098
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  14.  
>>> Horde_Registry->call() /usr/share/php/Horde/Registry/Caller.php:41
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  15.  
>>> Horde_Registry->callByPackage()  
>>> /usr/share/php/Horde/Registry.php:1088
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  16.  
>>> Mnemo_Api->getChangesByModSeq()  
>>> /usr/share/php/Horde/Registry.php:1131
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  17.  
>>> Mnemo_Api->getChanges() <webroot>/horde/mnemo/lib/Api.php:135
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  18. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:117
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  19. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  20. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  21. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  22. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  23. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  24. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  25. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  26. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  27. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  28. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  29. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  30. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  31. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  32. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  33. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  34. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  35. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  36. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>> [17-Feb-2017 17:39:54 Europe/Berlin] PHP  37. Mnemo_Api->listBy()  
>>> <webroot>/horde/mnemo/lib/Api.php:161
>>>
>>>
>>>>
>>>> First entry into listBy with empty $notepad eventually causes the  
>>>> recursive call to listBy(). This is supposed to be called with  
>>>> the actual $notepad parameter obtained by iterating over the  
>>>> results of the Mnemo::getSyncNotepads() call.
>>>> My guess is that this is returning a corrupt, or at least some  
>>>> unexpected, value. That's why I asked for the return of that  
>>>> method :)
>>>>
>>>
>>> AS I wrote, the return of the Method Mnemo::getSyncNotepads() if  
>>> this faulty Array ( [0] => )
>>
>> Ah. Sorry. I misunderstood your last email. I thought that was the  
>> return value of the listBY() call.
>>
>>
>>> I'll dive into every trace step and look whats causing the null  
>>> notepad call.
>>>
>>> One further question: If  listBy(...) is not able to handle  
>>> $notepad==null correctly, why is null specified as default  
>>> parameter for "notepad?
>>
>> listBy() is SUPPOSED to handle $notepad=null correctly. When that  
>> is the case, it loads all of the available notepads (the return  
>> from getSyncNotepads()) and then calls itself again once for each  
>> available notepad. The problem is THAT method is never supposed to  
>> return an empty value, and because it does, the same code path is  
>> executed over and over.
>
> Thanks!
> To sum up:
> a) we should investigate and fix it that returned value of  
> getSyncNotepads() is _not_empty.

Thanks Mike for explaining the horde internals. That made it quite  
easy to find the reason:
Looking into getSyncNotepads() reveals that the array is extracted  
from the 'sync_notepads' prefs.
This pref of the affected user is 'a:1:{i:0;N;}'. This is exactly the  
serialized representation of the faulty Array ( [0] => ).

In my opinion the fix should be
a) in the users prefs (easy to win), and
b) in the function to ensure that even with a faulty pref, the  
returned array is a correct array.

I recommend to enhance getSyncNotepads()  
(<webroot>/horde/mnemo/lib/Mnemo.php) to something like this:

static public function getSyncNotepads($prune = false)
{
         $haveRemoved = false;
         $cs = unserialize($GLOBALS['prefs']->getValue('sync_notepads'));
         array_filter($cs, function($var){return !is_null($var);} );   // added

         if (!empty($cs)) {
             if ($prune) {
                 $notepads =  self::listNotepads(true, Horde_Perms::DELETE);
                 $cscopy = array_flip($cs);
                 foreach ($cs as $c) {
                     if (empty($notepads[$c])) {
                         unset($cscopy[$c]);
                         $haveRemoved = true;
                     }
                 }
                 if ($haveRemoved) {
                     $GLOBALS['prefs']->setValue('sync_notepads',  
serialize(array_flip($cscopy)));
                 }
             }
             return $cs;
         }

         if ($cs = self::getDefaultNotepad(Horde_Perms::DELETE)) {
             return array($cs);
         }

         return array();
}


The only remaining question is how the faulty database entry was  
created but this is impossible to reconstruct..

Should we move the solution discussion to a bugreport?

Thanks,
Torben

>
>>
>> Off the top of my head, it sounds like it might be something wrong  
>> with their sync_notepads (or whatever it's called - I'm not in  
>> front of code at the moment) preference. You could try to re-set  
>> the value of this preference for one of the affected users to see  
>> if that helps.
>
> b) I already log the usernames of all affected accounts and will try  
> to fix it on this side als well.
>
> Thanks for your valuable input today!
>
> regards,
> Torben
>
>>
>>
>>> Thanks for your help,
>>> Torben
>>>
>>>
>>>
>>>
>>
>
>
> -- 
> Horde mailing list
> Frequently Asked Questions: http://horde.org/faq/
> To unsubscribe, mail: horde-unsubscribe at lists.horde.org





More information about the horde mailing list