Copyright (c) 2006-2013 osTicket http://www.osticket.com Released under the GNU General Public License WITHOUT ANY WARRANTY. See LICENSE.TXT for details. vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ include_once INCLUDE_DIR.'class.charset.php'; require_once INCLUDE_DIR.'class.variable.php'; class Format { function file_size($bytes) { if(!is_numeric($bytes)) return $bytes; if($bytes<1024) return $bytes.' bytes'; if($bytes < (900<<10)) return round(($bytes/1024),1).' kb'; return round(($bytes/1048576),1).' mb'; } function filesize2bytes($size) { switch (substr($size, -1)) { case 'M': case 'm': return (int)$size <<= 20; case 'K': case 'k': return (int)$size <<= 10; case 'G': case 'g': return (int)$size <<= 30; } return $size; } function filename($filename) { return preg_replace('/[^a-zA-Z0-9\-\._]/', '-', $filename); } function mimedecode($text, $encoding='UTF-8') { // Handle poorly or completely un-encoded header values ( if (function_exists('mb_detect_encoding')) if (($src_enc = mb_detect_encoding($text)) && (strcasecmp($src_enc, 'ASCII') !== 0)) return Charset::transcode($text, $src_enc, $encoding); if(function_exists('imap_mime_header_decode') && ($parts = imap_mime_header_decode($text))) { $str =''; foreach ($parts as $part) $str.= Charset::transcode($part->text, $part->charset, $encoding); $text = $str; } elseif($text[0] == '=' && function_exists('iconv_mime_decode')) { $text = iconv_mime_decode($text, 0, $encoding); } elseif(!strcasecmp($encoding, 'utf-8') && function_exists('imap_utf8')) { $text = imap_utf8($text); } return $text; } /** * Decodes filenames given in the content-disposition header according * to RFC5987, such as filename*=utf-8''filename.png. Note that the * language sub-component is defined in RFC5646, and that the filename * is URL encoded (in the charset specified) */ function decodeRfc5987($filename) { $match = array(); if (preg_match("/([\w!#$%&+^_`{}~-]+)'([\w-]*)'(.*)$/", $filename, $match)) // XXX: Currently we don't care about the language component. // The encoding hint is sufficient. return Charset::utf8(urldecode($match[3]), $match[1]); else return $filename; } /** * Json Encoder * */ function json_encode($what) { require_once (INCLUDE_DIR.'class.json.php'); return JsonDataEncoder::encode($what); } function phone($phone) { $stripped= preg_replace("/[^0-9]/", "", $phone); if(strlen($stripped) == 7) return preg_replace("/([0-9]{3})([0-9]{4})/", "$1-$2",$stripped); elseif(strlen($stripped) == 10) return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "($1) $2-$3",$stripped); else return $phone; } function truncate($string,$len,$hard=false) { if(!$len || $len>strlen($string)) return $string; $string = substr($string,0,$len); return $hard?$string:(substr($string,0,strrpos($string,' ')).' ...'); } function strip_slashes($var) { return is_array($var)?array_map(array('Format','strip_slashes'),$var):stripslashes($var); } function wrap($text, $len=75) { return $len ? wordwrap($text, $len, "\n", true) : $text; } function html_balance($html, $remove_empty=true) { if (!extension_loaded('dom')) return $html; if (!trim($html)) return $html; $doc = new DomDocument(); $xhtml = '' // Wrap the content in a
because libxml would use a

. "

$html
"; $doc->encoding = 'utf-8'; $doc->preserveWhitespace = false; $doc->recover = true; if (false === @$doc->loadHTML($xhtml)) return $html; if ($remove_empty) { // Remove empty nodes $xpath = new DOMXPath($doc); static $eE = array('area'=>1, 'br'=>1, 'col'=>1, 'embed'=>1, 'iframe' => 1, 'hr'=>1, 'img'=>1, 'input'=>1, 'isindex'=>1, 'param'=>1, 'div'=>1); do { $done = true; $nodes = $xpath->query('//*[not(text()) and not(node())]'); foreach ($nodes as $n) { if (isset($eE[$n->nodeName])) continue; $n->parentNode->removeChild($n); $done = false; } } while (!$done); } static $phpversion; if (!isset($phpversion)) $phpversion = phpversion(); $body = $doc->getElementsByTagName('body'); if (!$body->length) return $html; if ($phpversion > '5.3.6') { $html = $doc->saveHTML($doc->getElementsByTagName('body')->item(0)->firstChild); } else { $html = $doc->saveHTML(); $html = preg_replace('`^|<\?xml .+?>||||`', '', $html); # |
$`', '', trim($html)); } function html($html, $config=array()) { require_once(INCLUDE_DIR.'htmLawed.php'); $spec = false; if (isset($config['spec'])) $spec = $config['spec']; // Add in htmLawed defaults $config += array( 'balance' => 1, ); // Attempt to balance using libxml. htmLawed will corrupt HTML with // balancing to fix improper HTML at the same time. For instance, // some email clients may wrap block elements inside inline // elements. htmLawed will change such block elements to inlines to // make the HTML correct. if ($config['balance'] && extension_loaded('dom')) { $html = self::html_balance($html); $config['balance'] = 0; } return htmLawed($html, $config, $spec); } function html2text($html, $width=74, $tidy=true) { if (!$html) return $html; # Tidy html: decode, balance, sanitize tags if($tidy) $html = Format::html(Format::htmldecode($html), array('balance' => 1)); # See if advanced html2text is available (requires xml extension) if (function_exists('convert_html_to_text') && extension_loaded('dom') && ($text = convert_html_to_text($html, $width))) return $text; # Try simple html2text - insert line breaks after new line tags. $html = preg_replace( array(':
:i', ':()\s*:i', ':(

)\s*:i'), array("\n", "$1\n", "$1\n\n"), $html); # Strip tags, decode html chars and wrap resulting text. return Format::wrap( Format::htmldecode( Format::striptags($html, false)), $width); } static function __html_cleanup($el, $attributes=0) { static $eE = array('area'=>1, 'br'=>1, 'col'=>1, 'embed'=>1, 'hr'=>1, 'img'=>1, 'input'=>1, 'isindex'=>1, 'param'=>1); // We're dealing with closing tag if ($attributes === 0) return ""; // Remove iframe and embed without src (perhaps striped by spec) // It would be awesome to rickroll such entry :) if (in_array($el, array('iframe', 'embed')) && (!isset($attributes['src']) || empty($attributes['src']))) return ''; // Clean unexpected class values if (isset($attributes['class'])) { $classes = explode(' ', $attributes['class']); foreach ($classes as $i=>$a) // Unset all unsupported style classes -- anything but M$ if (strpos($a, 'Mso') !== 0) unset($classes[$i]); if ($classes) $attributes['class'] = implode(' ', $classes); else unset($attributes['class']); } // Clean browser-specific style attributes if (isset($attributes['style'])) { $styles = preg_split('/;\s*/S', html_entity_decode($attributes['style'])); $props = array(); foreach ($styles as $i=>&$s) { @list($prop, $val) = explode(':', $s); if (isset($props[$prop])) { unset($styles[$i]); continue; } $props[$prop] = true; // Remove unset or browser-specific style rules if (!$val || !$prop || $prop[0] == '-' || substr($prop, 0, 4) == 'mso-') unset($styles[$i]); // Remove quotes of properties without enclosed space if (!strpos($val, ' ')) $val = str_replace('"','', $val); else $val = str_replace('"',"'", $val); $s = "$prop:".trim($val); } unset($s); if ($styles) $attributes['style'] = Format::htmlchars(implode(';', $styles)); else unset($attributes['style']); } $at = ''; if (is_array($attributes)) { foreach ($attributes as $k=>$v) $at .= " $k=\"$v\""; return "<{$el}{$at}".(isset($eE[$el])?" /":"").">"; } else { return ""; } } function safe_html($html, $options=array()) { global $cfg; $options = array_merge(array( // Balance html tags 'balance' => 1, // Decoding special html char like < and > which // can be used to skip cleaning 'decode' => true ), $options); if ($options['decode']) $html = Format::htmldecode($html); // Remove HEAD and STYLE sections $html = preg_replace( array(':<(head|style|script).+?:is', # and