public function getFlInstance1() { Fl::loadClass('Fl_Html_Token'); $this->flInstance = new Fl_Html_Token(); $this->flInstance->tpl = 'smarty'; $this->flInstance->ld = '{='; $this->flInstance->rd = '=}'; }
public function getFlInstance() { Fl::loadClass('Fl_Html_TagToken'); $this->flInstance = new Fl_Html_TagToken(); $this->flInstance->tpl = 'smarty'; $this->flInstance->ld = '<&'; $this->flInstance->rd = '&>'; }
/** * * 模版语言的工厂 * @param Fl_Token $instance */ public static function factory(Fl_Base $instance, $new = false) { $class = 'Fl_Tpl_' . $instance->tpl; if (!$new && array_key_exists($class, self::$register)) { return self::$register[$class]; } Fl::loadClass($class); $new = new $class(); if (!$new) { self::$register[$class] = $new; } return $new; }
/** * * 模版语言的工厂 * @param Fl_Token $instance */ public static function factory(Fl_Base $instance, $new = false) { $tpl = strtolower($instance->tpl); $list = array('php' => 'PHP', 'smarty' => 'Smarty', 'xtemplate' => 'XTemplate'); if (isset($list[$tpl])) { $tpl = $list[$tpl]; } else { $tpl = 'Base'; } $class = 'Fl_Tpl_' . $tpl; if (!$new && array_key_exists($class, self::$register)) { return self::$register[$class]; } Fl::loadClass($class); $new = new $class(); if (!$new) { self::$register[$class] = $new; } return $new; }
<?php Fl::loadClass("Fl_Base"); /** * * CSS Compress * @author welefen * */ class Fl_Css_Compress extends Fl_Base { /** * * compress options * base compress is remove newline & comment * @var array */ public $options = array("remove_last_semicolon" => true, "remove_empty_selector" => true, "override_same_property" => true, "short_value" => true, "merge_property" => true, "sort_property" => true, "sort_selector" => true, "merge_selector" => true, "property_to_lower" => true); /** * * tpl options * @var array */ protected $tplOptions = array("override_same_property" => false, "short_value" => false, "merge_property" => false, "sort_property" => false, "sort_selector" => false, "merge_selector" => false, "property_to_lower" => false); /** * * remove useless class, used class will be set in $useClassList * @var boolean */ public $removeUnusedClass = false; /**
<?php Fl::loadClass('Fl_Html_Static'); Fl::loadClass('Fl_Html_Token'); /** * * HTML美化,HTML结构中不能包含TPL的TOKEN * @author welefen * */ class Fl_Html_Beautify extends Fl_Base { }
<?php Fl::loadClass("Fl_Base"); Fl::loadClass("Fl_Html_Static"); /** * * Html DOM Class * @author welefen * */ class Fl_Html_Dom extends Fl_Base { /** * run * @see Fl_Base::run() */ public function run() { if ($this->checkHasTplToken()) { $this->throwException("Dom can't not support tpl syntax in html"); } $ast = $this->getInstance("Fl_Html_Ast")->run(); } }
<?php Fl::loadClass("Fl_Token"); Fl::loadClass("Fl_Js_Static"); /** * * JS Tokenizar * @author welefen * */ class Fl_Js_Token extends Fl_Token { /** * * 是否允许是正则, 主要是正则和除法(/)比较像,要对他们进行区别 * @var boolean */ public $regexpAllowed = true; /** * * 是否进行简单的数据校验 * @var booelean */ public $validate = true; /** * * validate data, check number * @var array */ public $validateData = array('(' => 0, ')' => 0, '{' => 0, '}' => 0, '[' => 0, ']' => 0); /**
<?php Fl::loadClass('Fl_Base'); Fl::loadClass('Fl_Html_Static'); Fl::loadClass('Fl_Tpl'); /** * * XSS check & auto fixed * @author welefen * */ class Fl_Html_Xss extends Fl_Base { /** * * auto fixed * @var boolean */ public $auto_fixed = true; /** * * safe vars * @var array */ public $safe_vars = array(); /** * * xml document ? * @var boolean */ public $isXml = false;
/** * * beautify * @param array $ast */ public function beautifyAst($ast, $parentType = '') { $result = ''; $first = true; foreach ($ast as $item) { if (!$first) { $result = rtrim($result, FL_NEWLINE) . FL_NEWLINE; } $hasComment = false; if (count($item['value']['commentBefore'])) { $hasComment = true; } $comment = $this->beautifyComment($item['value']); if ($comment['remove']) { $result = rtrim($result, FL_NEWLINE); } $result .= $comment['value']; // if ($item['type'] === FL_TOKEN_HTML_TAG_END) { continue; } if ($first) { $first = false; } $indent = $newline = false; if ($item['type'] === FL_TOKEN_HTML_TAG) { $count = count($item['children']); if ($count > 1) { $indent = true; $newline = true; } elseif ($count === 1) { $c = $item['children'][$count - 1]; if ($c['type'] !== FL_TOKEN_HTML_TEXT) { $indent = true; $newline = true; } } } else { if (count($ast) > 1) { $newline = true; } if ($item['type'] === FL_TOKEN_HTML_DOCTYPE || $item['type'] === FL_TOKEN_HTML_SINGLE_TAG) { $newline = true; } if ($item['type'] === FL_TOKEN_HTML_STYLE_TAG || $item['type'] === FL_TOKEN_HTML_SCRIPT_TAG) { $newline = true; $indent = true; } } if ($item['type'] !== FL_TOKEN_HTML_TEXT) { $result .= $this->getIndentString(); } else { if (count($ast) > 1) { $result .= $this->getIndentString(); } } if ($parentType === FL_TOKEN_HTML_STYLE_TAG) { Fl::loadClass("Fl_Css_Static"); $value = Fl_Css_Static::getStyleDetail($item['value']['value']); if ($value['prefix']) { $result .= $value['prefix'] . FL_NEWLINE; } $result .= $this->beautify_special($value['value'], 'css'); if ($value['suffix']) { $result .= FL_NEWLINE . $value['suffix'] . FL_NEWLINE; } } elseif ($parentType === FL_TOKEN_HTML_SCRIPT_TAG) { $result .= $this->beautify_special($item['value']['value'], 'js'); } else { $result .= $item['value']['value']; } if ($newline) { $result .= FL_NEWLINE; } if ($indent) { $this->indent++; } if (count($item['children'])) { $type = $item['type']; if ($type === FL_TOKEN_HTML_SCRIPT_TAG) { $tagInfo = Fl_Html_Static::getScriptTagInfo($item['value']['value'], $this); //虽然是script标签,但不一定是Js if (!$tagInfo['script'] || $tagInfo['external']) { $type = ''; } } $children = $this->beautifyAst($item['children'], $type); if ($tagInfo['external'] && !strlen(trim($children))) { $result = rtrim($result, FL_NEWLINE); $newline = false; $indent = 2; } else { $result .= $children; } } $types = array(FL_TOKEN_HTML_TAG => 1, FL_TOKEN_HTML_SCRIPT_TAG => 1, FL_TOKEN_HTML_PRE_TAG => 1, FL_TOKEN_HTML_STYLE_TAG => 1, FL_TOKEN_HTML_TEXTAREA_TAG => 1); $this->preToken = $item['value']; if (isset($types[$item['type']])) { if ($newline) { $result = rtrim($result, FL_NEWLINE); $result .= FL_NEWLINE; } if ($indent) { $this->indent--; if ($indent === true) { $result .= $this->getIndentString(); } } if (!empty($item['end'])) { $this->preToken = $item['end']; $comment = $this->beautifyComment($item['end']); $result .= rtrim($comment['value'], FL_NEWLINE); } $result .= '</' . $item['tag'] . '>'; } } return $result; }
<?php /** * * Css Selector Token * 抛弃selector中的注释等对效果无用的代码 * 参见:http://www.w3.org/TR/selectors/ * @license MIT * @author welefen * @copyright 2011 - 2012 * @version 1.0 - 2012.02.25 * */ Fl::loadClass('Fl_Token'); Fl::loadClass('Fl_Css_Static'); class Fl_Css_SelectorToken extends Fl_Token { /** * * check value is valid ? * @var boolean */ public $check = true; /** * * prefix space for selector token * @var boolean */ public $preSpace = false; /** *
<?php require_once '/Users/welefen/Develop/git/stc/src/vender/Fl/src/Fl.class.php'; Fl::loadClass('Fl_Css_Token'); $content = file_get_contents('page.css'); $startTime = microtime(true); $instance = new Fl_Css_Token($content); $instance->run(); $endTime = microtime(true); echo ($endTime - $startTime) * 1000 . "\n";
<?php /** * * css值的token分析 * @author welefen * */ Fl::loadClass("Fl_Token"); Fl::loadClass("Fl_Css_Static"); class Fl_Css_ValueToken extends Fl_Token { /** * * 当前分析css属性值对应的属性名 * @var string */ public $property = ""; /** * 执行 * @see Fl_Token::run() */ public function run($property = "") { $this->property = strtolower($property); $tokens = array(); while (true) { $token = $this->getNextToken(); if (empty($token)) { break; }
<?php Fl::loadClass('Fl_Token'); Fl::loadClass('Fl_Html_Static'); /** * * HTML Tokenizar * */ class Fl_Html_Token extends Fl_Token { /** * @var boolean */ public $validate = true; /** * * 当前检测的是否是XML * @var boolean */ public $isXML = false; /** * * html里不能过滤空格字符 * @var array */ protected $whiteSpace = array("\n" => 1, "\t" => 1, "\f" => 1); /** * get next token * @see Fl_Token::getNextToken() */
/** * * 获取tag的属性 * @param string $tag */ public static function getTagAttrs($tag = '', Fl_Base $obj) { Fl::loadClass('Fl_Html_TagToken'); $instance = new Fl_Html_TagToken(); $instance->tpl = $obj->tpl; $instance->ld = $obj->ld; $instance->rd = $obj->rd; return $instance->getAttrs($tag); }
/** * * 获取模版语法的Token * @param object $obj */ public function getTplToken() { if (!$this->checkHasTplToken() || !$this->startWith($this->ld)) { return false; } Fl::loadClass('Fl_Tpl'); return Fl_Tpl::factory($this)->getToken($this); }
/** * * compress style * @param array $token */ public function compressStyle($token) { if (!$this->options['compress_tag']) { return $token['value']; } $info = Fl_Html_Static::splitSpecialValue($token['value'], 'style', $this); $content = trim($info['content']); if ($this->options['remove_empty_style'] && !$content) { return ''; } if ($this->options['compress_inline_css'] && $content) { Fl::loadClass("Fl_Css_Static"); $value = Fl_Css_Static::getStyleDetail($content); $containTpl = $this->containTpl($value['value']); //自定义内联CSS压缩方法 if (!$containTpl && $this->cssCompressMethod) { $content = call_user_func($this->cssCompressMethod, $value['value'], $this); } else { $content = $this->getInstance("Fl_Css_Compress", $value['value'])->run(); } } if ($this->options['remove_optional_attrs']) { $tagInfo = $this->getInstance("Fl_Html_TagToken", $info['tag_start'])->run(); $tagInfo['lowerTag'] = strtolower($tagInfo['tag']); $info['tag_start'] = $this->compressStartTag($tagInfo); } if ($this->options['merge_adjacent_css']) { $endStyle = '</style>'; $outputLen = strlen($this->output); $last = substr($this->output, $outputLen - 8); if (strtolower($last) === $endStyle) { $this->output = substr($this->output, 0, $outputLen - 8); return $content . $info['tag_end']; } } return $info['tag_start'] . $content . $info['tag_end']; }
<?php $text = file_get_contents("1.text"); require_once dirname(dirname(__FILE__)) . '/src/Fl.class.php'; Fl::loadClass('Fl_Html_Compress'); $instance = new Fl_Html_Compress($text); $instance->tpl = ''; $instance->ld = ''; $instance->rd = ''; $startTime = microtime(true); #xhprof_enable ( XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY ); xhprof_enable(); $options = array("compress_tag" => true); $output = $instance->run($options); $xhprof_data = xhprof_disable(); $endTime = microtime(true); $path = "/home/welefen/Documents/www/"; include_once $path . "xhprof_lib/utils/xhprof_lib.php"; include_once $path . "xhprof_lib/utils/xhprof_runs.php"; $xhprof_runs = new XHProfRuns_Default(); echo '<div>Time: ' . ($endTime - $startTime) . 's</div>'; $rate = number_format((strlen($text) - strlen($output)) * 100 / strlen($text), 2); echo strlen($text) . "/" . strlen($output) . "<br/>" . $rate . "%<br>"; $run_id = $xhprof_runs->save_run($xhprof_data, "sourcejoy"); echo '<iframe src="http://www/xhprof_html/?run=' . $run_id . '&source=sourcejoy" frameborder="0" width="100%" height="950px" border="0"></iframe>';
<?php /** * * 模版语言为Smarty的分析方法 * @author welefen * */ Fl::loadClass('Fl_Tpl_Interface'); class Fl_Tpl_Smarty implements Fl_Tpl_Interface { /** * * 输出模版语法的正则 * @var RegexIterator */ public $tplOutputPattern = '/^\\s*{LD}\\s*\\$[\\w\\$\\_].*?/'; /** * * 获取模版语法的Token * @param object $instance */ public function getToken(Fl_Token &$instance) { return $instance->getMatched($instance->ld, $instance->rd, true); } /** * * 检测当前的tpl是否会输出 * @param string $tpl */
/** * * 获取对应token类的实例 */ public function getTokenInstance($tokenClass = '') { if (!$tokenClass) { $tokenClass = $this->tokenClass; } if (!$tokenClass) { $this->throwException($tokenClass . ' must be a string'); } Fl::loadClass($tokenClass); $instance = new $tokenClass($this->text); $instance->tpl = $this->tpl; $instance->ld = $this->ld; $instance->rd = $this->rd; return $instance; }
/** * * 获取expression里js部分的值 */ public function getJsText() { $result = ''; Fl::loadClass('Fl_Js_Token'); while (($char = $this->getNextChar()) !== false) { $result .= $char; if ($char === ')') { $instance = new Fl_Js_Token($result); $instance->validate = false; $output = $instance->run(); if ($instance->validateData['('] === $instance->validateData[')']) { break; } } } return $result; }
/** * * 压缩模版语法 * @param array $token */ public function compressTpl($token) { Fl::loadClass('Fl_Tpl'); return Fl_Tpl::factory($this)->compress($token['value'], $this); }
<?php /** * * css auto complete class * @author welefen * */ Fl::loadClass('Fl_Base'); class Fl_Css_AutoComplete extends Fl_Base { /** * * css里的配置背景图片的正则 * @var RegExp */ protected $backgroundImgPattern = '/url\\s*\\(\\s*([\'\\"]?)([\\w\\-\\/\\.]+\\.(?:png|jpg|gif|jpeg|ico|cur))(?:\\?[^\\?\'\\"\\)\\s]*)?\\1\\s*\\)/ies'; /** * * 匹配keyframes的正则 * @var RegExp */ protected $keyFramesPattern = '/@(?:\\-(webkit|moz|ms|o)\\-)?keyframes\\s+([\\w\\-]+)/ies'; /** * * 可以自动完成的属性 * @var array */ protected $completeAttrs = array('radius' => array('w3c'), 'box-shadow' => array('w3c'), 'background' => array('webkit', 'o', 'w3c'), 'opacity' => array('filter'), 'transform' => array('webkit', 'ms', 'w3c'), 'perspective' => array('webkit', 'moz', 'ms', 'w3c'), 'transition' => array('webkit', 'w3c'), 'box-sizing' => array('w3c'), 'background-size' => array('w3c'), 'background-clip' => array('w3c'), 'column' => array('webkit', 'moz', 'w3c'), 'animation' => array('w3c', 'webkit'), 'tab-size' => array('moz', 'o', 'w3c'), 'keyframes' => array('webkit', 'w3c'), 'user-select' => array('webkit', 'w3c', 'moz', 'ms')); /** *
/** * * 获取对应class的实例 */ public function getInstance($class = '', $text = '') { Fl::loadClass($class); $instance = new $class($text ? $text : $this->text, $this->encoding); $instance->tpl = $this->tpl; $instance->ld = $this->ld; $instance->rd = $this->rd; return $instance; }
<?php include_once '../src/Fl.class.php'; Fl::loadClass('fl_html_xss'); $content = '<div>html content {{a}} ddd {{{safe_a}}} {{{unsafe_var}}}</div>'; $instance = new Fl_Html_Xss($content, 'utf8'); $instance->tpl = 'XTemplate'; $instance->ld = '{{'; $instance->rd = '}}'; //安全变量列表,支持正则 $instance->safe_vars = array('safe_a'); $result = $instance->run(array('url' => 'escape_url', 'html' => 'escape_html', 'js' => 'escape_js', 'callback' => 'escape_callback', 'data' => 'escape_data', 'event' => 'escape_event', 'noescape' => 'no_escape', 'xml' => 'escape_xml')); echo $result . "\n";
<?php /** * * js ast class * @author welefen * */ Fl::loadClass('Fl_Base'); Fl::loadClass('Fl_Js_Static'); class Fl_Js_Ast extends Fl_Base { /** * * 构建的语法树是否要带上token的相关信息 * @var boolean */ public $embedToken = false; /** * * token类实例 * @var object */ protected $tokenInstance = null; /** * * 上一个token * @var array or false */ protected $prevToken = false; /**
/** * * Calculating a selector's specificity * see more: http://www.w3.org/TR/selectors/#specificity * @param array $selectorTokens */ public static function getSelectorSpecificity($selectorTokens = array()) { if (!is_array($selectorTokens)) { $selectorTokens = self::getSelectorTokens($selectorTokens); } $score = array(0, 0, 0); $notPattern = '/^\\:not\\(/ies'; foreach ($selectorTokens as $item) { $type = $item['type']; switch ($type) { case FL_TOKEN_CSS_SELECTOR_ID: $score[0]++; break; case FL_TOKEN_CSS_SELECTOR_TYPE: case FL_TOKEN_CSS_SELECTOR_PSEUDO_ELEMENT: $score[2]++; break; case FL_TOKEN_CSS_SELECTOR_CLASS: case FL_TOKEN_CSS_SELECTOR_ATTRIBUTES: $score[1]++; break; case FL_TOKEN_CSS_SELECTOR_PSEUDO_CLASS: $value = $item['value']; //:not(xxx) if (preg_match($notPattern, $value)) { $value = trim(preg_replace($notPattern, "", $value)); $value = substr($value, 0, strlen($value) - 1); Fl::loadClass('Fl_Css_SelectorToken'); $instance = new Fl_Css_SelectorToken($value); $tokens = $instance->run(); $notScore = Fl_Css_Static::getSelectorSpecificity($tokens[0]); $score[0] += $notScore[0]; $score[1] += $notScore[1]; $score[2] += $notScore[2]; } else { $score[1]++; } break; } } return $score; }
function get_test_result($class, $text, $properties = array(), $options = array()) { require_once dirname(dirname(__FILE__)) . "/src/Fl.class.php"; Fl::loadClass($class); $instance = new $class($text); foreach ($properties as $name => $value) { $instance->{$name} = $value; } try { $output = $instance->run($options); } catch (Fl_Exception $e) { $output = $e->message; } return $output; }