Not one to miss out on a trend, I'll give it a shot, too :)
This will try and find periods or spaces to cut at within a given tolerance, favoring longer texts if more than one qualified cut length exists within tolerance ($cutZone).
function cutstr($str, $length, $tolerance = 5) {
    $cutZone   = substr($str, $length - $tolerance, 2 * $tolerance);
    $posPeriod = strrpos($cutZone, '.');
    $posSpace  = strrpos($cutZone, ' ');
    $ellipsis  = '…';
    if (strlen($str) <= $length + $tolerance) {
        // $str is shorter than $length+$tolerance - no cut, no ellipsis
        $posCut   = strlen($str);
        $ellipsis = '';
    } elseif ($posPeriod !== false) {
        // $str has period within tolerance - cut at period
        $posCut = $length - $tolerance + $posPeriod;
    } elseif ($posSpace !== false) {
        // $str has space within tolerance - cut at space
        $posCut = $length - $tolerance + $posSpace;
    } else {
        // Nothing to do - cut word
        $posCut = $length;
    }
    return substr($str, 0, $posCut) . $ellipsis;
}
(DemoDemo)
In general, never fetch more data from the DB than needed. You can easily just select LEFT(<column>, <lengt+tolerance>) from the DB and then perform the cutting on this string.
Update
Favoring longer texts.