Index: branches/1.1dev/lib/Utilities.inc.php
===================================================================
--- branches/1.1dev/lib/Utilities.inc.php	(revision 648)
+++ branches/1.1dev/lib/Utilities.inc.php	(revision 649)
@@ -9,17 +9,56 @@
  * Print variable dump.
  *
- * @param  mixed $var      Variable to dump.
- * @param  bool  $display   Hide the dump in HTML comments?
- * @param  bool  $var_dump Use var_dump instead of print_r.
- */
-function dump($var, $display=false, $var_dump=false)
-{
-	echo $display ? "\n<br /><pre>\n" : "\n\n\n<!--\n";
-	if ($var_dump) {
+ * @param  mixed    $var        The variable to dump.
+ * @param  bool     $display    Print the dump in <pre> tags or hide it in html comments (non-CLI only).
+ * @param  bool     $dump_method   Dump method. See SC_DUMP_* constants.
+ * @param  string   $file       Value of __FILE__.
+ * @param  string   $line       Value of __LINE__
+ */
+define('SC_DUMP_PRINT_R', 0);
+define('SC_DUMP_VAR_DUMP', 1);
+define('SC_DUMP_VAR_EXPORT', 2);
+function dump($var, $display=false, $dump_method=SC_DUMP_PRINT_R, $file='', $line='')
+{
+    $app =& App::getInstance();
+
+    if ('cli' === php_sapi_name() || defined('_CLI')) {
+        echo "DUMP FROM: $file $line\n";
+    } else {
+        echo $display ? "\n<br />DUMP <strong>$file $line</strong><br /><pre>\n" : "\n<!-- DUMP $file $line\n";
+    }
+
+    switch ($dump_method) {
+    case SC_DUMP_PRINT_R:
+    default:
+        // Print human-readable descriptions of invisible types.
+        if (null === $var) {
+            echo '(null)';
+        } else if (true === $var) {
+            echo '(bool: true)';
+        } else if (false === $var) {
+            echo '(bool: false)';
+        } else if (is_scalar($var) && '' === $var) {
+            echo '(empty string)';
+        } else if (is_scalar($var) && preg_match('/^\s+$/', $var)) {
+            echo '(only white space)';
+        } else {
+            print_r($var);
+        }
+        break;
+
+    case SC_DUMP_VAR_DUMP:
         var_dump($var);
-    } else {
-        print_r($var);
-    }
-	echo $display ?  "\n</pre><br />\n" : "\n-->\n\n\n";
+        break;
+
+    case SC_DUMP_VAR_EXPORT:
+        var_export($var);
+        break;
+    }
+
+    if ('cli' === php_sapi_name() || defined('_CLI')) {
+        echo "\n";
+    } else {
+        echo $display ? "\n</pre><br />\n" : "\n-->\n";
+    }
 }
 
@@ -43,6 +82,6 @@
  * Return dump as cleaned text. Useful for dumping data into emails.
  *
- * @param  mixed $var      Variable to dump.
- *
+ * @param  array    $var        Variable to dump.
+ * @param  strong   $indent     A string to prepend indented lines (tab for example).
  * @return string Dump of var.
  */
@@ -52,5 +91,5 @@
     if (is_array($var)) {
         foreach ($var as $k=>$v) {
-            $k = ucfirst(strtolower(str_replace(array('_', '  '), ' ', $k)));
+            $k = ucfirst(mb_strtolower(str_replace(array('_', '  '), ' ', $k)));
             if (is_array($v)) {
                 $output .= sprintf("\n%s%s: %s\n", $indent, $k, fancyDump($v, $indent . $indent));
@@ -62,5 +101,5 @@
         $output .= sprintf("%s%s\n", $indent, $var);
     }
-    return $output;
+    return preg_replace(['/^[ \t]+$/', '/\n\n\n+/'], ['', "\n\n"], $output);
 }
 
@@ -215,22 +254,28 @@
  * @since   29 Mar 2006 13:48:49
  */
-function truncate($str, $len, $where='end', $delim='âŠ')
-{
-    if ($len <= 3 || mb_strlen($str) <= 3) {
-        return '';
-    }
-    $part1 = floor(($len - 3) / 2);
-    $part2 = ceil(($len - 3) / 2);
+function truncate($str, $len=50, $where='end', $delim='âŠ')
+{
+    $dlen = mb_strlen($delim);
+    if ($len <= $dlen || mb_strlen($str) <= $dlen) {
+        return substr($str, 0, $len);
+    }
+    $part1 = floor(($len - $dlen) / 2);
+    $part2 = ceil(($len - $dlen) / 2);
+
+    if ($len > ini_get('pcre.backtrack_limit')) {
+        logMsg(sprintf('Asked to truncate string len of %s > pcre.backtrack_limit of %s', $len, ini_get('pcre.backtrack_limit')), LOG_DEBUG, __FILE__, __LINE__);
+        ini_set('pcre.backtrack_limit', $len);
+    }
+
     switch ($where) {
     case 'start' :
-        return preg_replace(array(sprintf('/^.{4,}(.{%s})$/sU', $part1 + $part2), '/\s*\.{3,}\s*/sU'), array($delim . '$1', $delim), $str);
-        break;
+        return preg_replace(array(sprintf('/^.{%s,}(.{%s})$/su', $dlen + 1, $part1 + $part2), sprintf('/\s*%s{%s,}\s*/su', preg_quote($delim), $dlen)), array($delim . '$1', $delim), $str);
+
+    case 'middle' :
+        return preg_replace(array(sprintf('/^(.{%s}).{%s,}(.{%s})$/su', $part1, $dlen + 1, $part2), sprintf('/\s*%s{%s,}\s*/su', preg_quote($delim), $dlen)), array('$1' . $delim . '$2', $delim), $str);
+
+    case 'end' :
     default :
-    case 'middle' :
-        return preg_replace(array(sprintf('/^(.{%s}).{4,}(.{%s})$/sU', $part1, $part2), '/\s*\.{3,}\s*/sU'), array('$1' . $delim . '$2', $delim), $str);
-        break;
-    case 'end' :
-        return preg_replace(array(sprintf('/^(.{%s}).{4,}$/sU', $part1 + $part2), '/\s*\.{3,}\s*/sU'), array('$1' . $delim, $delim), $str);
-        break;
+        return preg_replace(array(sprintf('/^(.{%s}).{%s,}$/su', $part1 + $part2, $dlen + 1), sprintf('/\s*%s{%s,}\s*/su', preg_quote($delim), $dlen)), array('$1' . $delim, $delim), $str);
     }
 }
