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>|?body>|?head>|
`', '', $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 "{$el}>";
// 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 "{$el}>";
}
}
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).+?\1>:is', # and