Chip 扫描报告

chip.phar check -o 'output.html' -r html './typecho/'

2019-05-03 19:32:50 ~ 2019-05-03 19:32:52
扫描PHP文件204个,发现127处隐患。

扫描文件总览

文件名 总数 严重 高危 警告 信息
./typecho/admin/extending.php 1 0 1 0 0
./typecho/var/Typecho/Plugin.php 1 0 1 0 0
./typecho/var/Typecho/Request.php 4 0 2 2 0
./typecho/var/Typecho/Db.php 6 0 5 1 0
./typecho/var/Typecho/Http/Client.php 2 0 1 1 0
./typecho/var/Typecho/AutoP.php 4 0 4 0 0
./typecho/var/Typecho/Db/Query.php 1 0 1 0 0
./typecho/var/Typecho/Router.php 1 0 1 0 0
./typecho/var/Typecho/Validate.php 3 0 3 0 0
./typecho/var/Typecho/Common.php 14 0 5 9 0
./typecho/var/Typecho/I18n/GetText.php 1 1 0 0 0
./typecho/var/Typecho/Widget.php 5 0 4 1 0
./typecho/var/Typecho/Router/Parser.php 1 0 1 0 0
./typecho/var/Markdown.php 1 0 0 1 0
./typecho/var/Widget/Abstract/Contents.php 2 0 2 0 0
./typecho/var/Widget/Options/General.php 1 0 1 0 0
./typecho/var/Widget/Comments/Archive.php 1 0 1 0 0
./typecho/var/Widget/Comments/Recent.php 1 0 1 0 0
./typecho/var/Widget/Comments/Ping.php 1 0 1 0 0
./typecho/var/Widget/Comments/Admin.php 1 0 1 0 0
./typecho/var/Widget/Contents/Page/List.php 1 0 1 0 0
./typecho/var/Widget/Contents/Page/Admin.php 2 0 2 0 0
./typecho/var/Widget/Contents/Post/Recent.php 1 0 1 0 0
./typecho/var/Widget/Contents/Post/Edit.php 5 0 4 1 0
./typecho/var/Widget/Contents/Post/Admin.php 2 0 2 0 0
./typecho/var/Widget/Contents/Attachment/Unattached.php 1 0 1 0 0
./typecho/var/Widget/Contents/Attachment/Related.php 1 0 1 0 0
./typecho/var/Widget/Contents/Attachment/Admin.php 2 0 2 0 0
./typecho/var/Widget/Contents/Related/Author.php 1 0 1 0 0
./typecho/var/Widget/Contents/Related.php 1 0 1 0 0
./typecho/var/Widget/Archive.php 8 0 8 0 0
./typecho/var/Widget/Plugins/Config.php 2 0 2 0 0
./typecho/var/Widget/Plugins/Edit.php 9 0 9 0 0
./typecho/var/Widget/XmlRpc.php 1 0 1 0 0
./typecho/var/Widget/Do.php 1 0 0 1 0
./typecho/var/Widget/Upgrade.php 3 0 3 0 0
./typecho/var/Widget/Menu.php 3 0 3 0 0
./typecho/var/Widget/Users/Profile.php 3 0 3 0 0
./typecho/var/Widget/Users/Admin.php 1 0 1 0 0
./typecho/var/Widget/Options.php 1 0 1 0 0
./typecho/var/Widget/Metas/Category/List.php 1 0 1 0 0
./typecho/var/Widget/Metas/Tag/Cloud.php 2 0 1 1 0
./typecho/var/Widget/Metas/Tag/Admin.php 1 0 1 0 0
./typecho/var/Widget/Themes/Config.php 1 0 1 0 0
./typecho/var/Widget/Themes/List.php 1 0 1 0 0
./typecho/var/Widget/Themes/Edit.php 1 0 1 0 0
./typecho/var/Widget/Feedback.php 1 0 1 0 0
./typecho/var/Json.php 4 0 1 3 0
./typecho/var/Upgrade.php 1 0 1 0 0
./typecho/var/Helper.php 3 0 2 1 0
./typecho/var/IXR/Server.php 3 0 3 0 0
./typecho/var/IXR/Message.php 1 0 1 0 0
./typecho/var/IXR/Client.php 1 0 1 0 0
./typecho/var/HyperDown.php 5 0 5 0 0

扫描漏洞总览

./typecho/admin/extending.php

等级 函数 说明
danger - 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
8:    throw new Typecho_Plugin_Exception(_t('页面不存在'), 404);
9:}
10:
11:list ($pluginName, $file) = explode('/', trim($panel, '/'), 2);
12:
13:require_once $options->pluginDir($pluginName) . '/' . $panel;
14:

./typecho/var/Typecho/Plugin.php

等级 函数 说明
danger __call call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
479:    public function __call($component, $args)
480:    {
481:        $component = $this->_handle . ':' . $component;
482:        $last = count($args);
483:        $args[$last] = $last > 0 ? $args[0] : false;
484:
485:        if (isset(self::$_plugins['handles'][$component])) {
486:            $args[$last] = NULL;
487:            $this->_signal = true;
488:            foreach (self::$_plugins['handles'][$component] as $callback) {
489:                $args[$last] = call_user_func_array($callback, $args);
490:            }
491:        }
492:
493:        return $args[$last];
494:    }

./typecho/var/Typecho/Request.php

等级 函数 说明
danger _applyFilter array_map第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
159:    private function _applyFilter($value)
160:    {
161:        if ($this->_filter) {
162:            foreach ($this->_filter as $filter) {
163:                $value = is_array($value) ? array_map($filter, $value) :
164:                call_user_func($filter, $value);
165:            }
166:
167:            $this->_filter = array();
168:        }
169:
170:        return $value;
171:    }
danger _applyFilter call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
159:    private function _applyFilter($value)
160:    {
161:        if ($this->_filter) {
162:            foreach ($this->_filter as $filter) {
163:                $value = is_array($value) ? array_map($filter, $value) :
164:                call_user_func($filter, $value);
165:            }
166:
167:            $this->_filter = array();
168:        }
169:
170:        return $value;
171:    }
warning __construct array_filter第1个参数,请使用闭包函数
代码
204:    public function __construct()
205:    {
206:        if (false === self::$_httpParams) {
207:            self::$_httpParams = array_filter(array_merge($_POST, $_GET),
208:                array('Typecho_Common', 'checkStrEncoding'));
209:        }
210:    }
warning setParams array_filter第1个参数,请使用闭包函数
代码
371:    public function setParams($params)
372:    {
373:        //处理字符串
374:        if (!is_array($params)) {
375:            parse_str($params, $out);
376:            $params = $out;
377:        }
378:
379:        $this->_params = array_merge($this->_params,
380:            array_filter($params, array('Typecho_Common', 'checkStrEncoding')));
381:    }

./typecho/var/Typecho/Db.php

等级 函数 说明
danger __construct call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
114:    public function __construct($adapterName, $prefix = 'typecho_')
115:    {
116:        /** 获取适配器名称 */
117:        $this->_adapterName = $adapterName;
118:
119:        /** 数据库适配器 */
120:        $adapterName = 'Typecho_Db_Adapter_' . $adapterName;
121:
122:        if (!call_user_func(array($adapterName, 'isAvailable'))) {
123:            throw new Typecho_Db_Exception("Adapter {$adapterName} is not available");
124:        }
125:
126:        $this->_prefix = $prefix;
127:
128:        /** 初始化内部变量 */
129:        $this->_pool = array();
130:        $this->_connectedPool = array();
131:        $this->_config = array();
132:
133:        //实例化适配器对象
134:        $this->_adapter = new $adapterName();
135:    }
warning __construct 动态创建类对象,可能存在远程代码执行的隐患
代码
114:    public function __construct($adapterName, $prefix = 'typecho_')
115:    {
116:        /** 获取适配器名称 */
117:        $this->_adapterName = $adapterName;
118:
119:        /** 数据库适配器 */
120:        $adapterName = 'Typecho_Db_Adapter_' . $adapterName;
121:
122:        if (!call_user_func(array($adapterName, 'isAvailable'))) {
123:            throw new Typecho_Db_Exception("Adapter {$adapterName} is not available");
124:        }
125:
126:        $this->_prefix = $prefix;
127:
128:        /** 初始化内部变量 */
129:        $this->_pool = array();
130:        $this->_connectedPool = array();
131:        $this->_config = array();
132:
133:        //实例化适配器对象
134:        $this->_adapter = new $adapterName();
135:    }
danger select call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
290:    public function select()
291:    {
292:        $args = func_get_args();
293:        return call_user_func_array(array($this->sql(), 'select'), $args ? $args : array('*'));
294:    }
danger fetchAll call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
381:    public function fetchAll($query, array $filter = NULL)
382:    {
383:        //执行查询
384:        $resource = $this->query($query, self::READ);
385:        $result = array();
386:
387:        /** 取出过滤器 */
388:        if (!empty($filter)) {
389:            list($object, $method) = $filter;
390:        }
391:
392:        //取出每一行
393:        while ($rows = $this->_adapter->fetch($resource)) {
394:            //判断是否有过滤器
395:            $result[] = $filter ? call_user_func(array(&$object, $method), $rows) : $rows;
396:        }
397:
398:        return $result;
399:    }
danger fetchRow 动态调用方法,可能存在远程代码执行的隐患
代码
408:    public function fetchRow($query, array $filter = NULL)
409:    {
410:        $resource = $this->query($query, self::READ);
411:
412:        /** 取出过滤器 */
413:        if ($filter) {
414:            list($object, $method) = $filter;
415:        }
416:
417:        return ($rows = $this->_adapter->fetch($resource)) ?
418:        ($filter ? $object->$method($rows) : $rows) :
419:        array();
420:    }
danger fetchObject 动态调用方法,可能存在远程代码执行的隐患
代码
429:    public function fetchObject($query, array $filter = NULL)
430:    {
431:        $resource = $this->query($query, self::READ);
432:
433:        /** 取出过滤器 */
434:        if ($filter) {
435:            list($object, $method) = $filter;
436:        }
437:
438:        return ($rows = $this->_adapter->fetchObject($resource)) ?
439:        ($filter ? $object->$method($rows) : $rows) :
440:        new stdClass();
441:    }

./typecho/var/Typecho/Http/Client.php

等级 函数 说明
danger get call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
37:    public static function get()
38:    {
39:        $adapters = func_get_args();
40:
41:        if (empty($adapters)) {
42:            $adapters = array();
43:            $adapterFiles = glob(dirname(__FILE__) . '/Client/Adapter/*.php');
44:            foreach ($adapterFiles as $file) {
45:                $adapters[] = substr(basename($file), 0, -4);
46:            }
47:        }
48:
49:        foreach ($adapters as $adapter) {
50:            $adapterName = 'Typecho_Http_Client_Adapter_' . $adapter;
51:            if (Typecho_Common::isAvailableClass($adapterName) && call_user_func(array($adapterName, 'isAvailable'))) {
52:                return new $adapterName();
53:            }
54:        }
55:
56:        return false;
57:    }
warning get 动态创建类对象,可能存在远程代码执行的隐患
代码
37:    public static function get()
38:    {
39:        $adapters = func_get_args();
40:
41:        if (empty($adapters)) {
42:            $adapters = array();
43:            $adapterFiles = glob(dirname(__FILE__) . '/Client/Adapter/*.php');
44:            foreach ($adapterFiles as $file) {
45:                $adapters[] = substr(basename($file), 0, -4);
46:            }
47:        }
48:
49:        foreach ($adapters as $adapter) {
50:            $adapterName = 'Typecho_Http_Client_Adapter_' . $adapter;
51:            if (Typecho_Common::isAvailableClass($adapterName) && call_user_func(array($adapterName, 'isAvailable'))) {
52:                return new $adapterName();
53:            }
54:        }
55:
56:        return false;
57:    }

./typecho/var/Typecho/AutoP.php

等级 函数 说明
danger cutByBlock preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
49:    private function cutByBlock($text)
50:    {
51:        $space = "( | )";
52:        $text = str_replace("\r\n", "\n", trim($text));
53:        $text = preg_replace("/{$space}*\n{$space}*/is", "\n", $text);
54:        $text = preg_replace("/\s*<p:([0-9]{4})\/>\s*/is", "</p><p:\\1/><p>", $text);
55:        $text = preg_replace("/\n{2,}/", "</p><p>", $text);
56:        $text = nl2br($text);
57:        $text = preg_replace("/(<p>)?\s*<p:([0-9]{4})\/>\s*(<\/p>)?/is", "<p:\\2/>", $text);
58:        $text = preg_replace("/<p>{$space}*<\/p>/is", '', $text);
59:        $text = preg_replace("/\s*<p>\s*$/is", '', $text);
60:        $text = preg_replace("/^\s*<\/p>\s*/is", '', $text);
61:        return $text;
62:    }
danger cutByBlock preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
49:    private function cutByBlock($text)
50:    {
51:        $space = "( | )";
52:        $text = str_replace("\r\n", "\n", trim($text));
53:        $text = preg_replace("/{$space}*\n{$space}*/is", "\n", $text);
54:        $text = preg_replace("/\s*<p:([0-9]{4})\/>\s*/is", "</p><p:\\1/><p>", $text);
55:        $text = preg_replace("/\n{2,}/", "</p><p>", $text);
56:        $text = nl2br($text);
57:        $text = preg_replace("/(<p>)?\s*<p:([0-9]{4})\/>\s*(<\/p>)?/is", "<p:\\2/>", $text);
58:        $text = preg_replace("/<p>{$space}*<\/p>/is", '', $text);
59:        $text = preg_replace("/\s*<p>\s*$/is", '', $text);
60:        $text = preg_replace("/^\s*<\/p>\s*/is", '', $text);
61:        return $text;
62:    }
danger parse preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
132:    public function parse($text)
133:    {
134:        /** 重置计数器 */
135:        $this->_uniqueId = 0;
136:        $this->_blocks = array();
137:        
138:        /** 将已有的段落后面的换行处理掉 */
139:        $text = preg_replace(array("/<\/p>\s+<p(\s*)/is", "/\s*<br\s*\/?>\s*/is"), array("</p><p\\1", "<br />"), trim($text));
140:        
141:        /** 将所有非自闭合标签解析为唯一的字符串 */
142:        $foundTagCount = 0;
143:        $textLength = strlen($text);
144:        $uniqueIdList = array();
145:
146:        if (preg_match_all("/<\/\s*([a-z0-9]+)>/is", $text, $matches, PREG_OFFSET_CAPTURE)) {
147:            foreach ($matches[0] as $key => $match) {
148:                $tag = $matches[1][$key][0];
149:                
150:                $leftOffset = $match[1] - $textLength;
151:                $posSingle = strrpos($text, '<' . $tag . '>', $leftOffset);
152:                $posFix = strrpos($text, '<' . $tag . ' ', $leftOffset);
153:                $pos = false;
154:                
155:                switch (true) {
156:                    case (false !== $posSingle && false !== $posFix):
157:                        $pos = max($posSingle, $posFix);
158:                        break;
159:                    case false === $posSingle && false !== $posFix:
160:                        $pos = $posFix;
161:                        break;
162:                    case false !== $posSingle && false === $posFix:
163:                        $pos = $posSingle;
164:                        break;
165:                    default:
166:                        break;
167:                }
168:                
169:                if (false !== $pos) {
170:                    $uniqueId = $this->makeUniqueId();
171:                    $uniqueIdList[$uniqueId] = $tag;
172:                    $tagLength = strlen($tag);
173:                    
174:                    $text = substr_replace($text, $uniqueId, $pos + 1 + $tagLength, 0);
175:                    $text = substr_replace($text, $uniqueId, $match[1] + 7 + $foundTagCount * 10 + $tagLength, 0); // 7 = 5 + 2
176:                    $foundTagCount ++;
177:                }
178:            }
179:        }
180:        
181:        foreach ($uniqueIdList as $uniqueId => $tag) {
182:            $text = preg_replace_callback("/<({$tag})({$uniqueId})([^>]*)>(.*)<\/\\1\\2>/is",
183:                array($this, 'replaceBlockCallback'), $text, 1);
184:        }
185:        
186:        $text = $this->cutByBlock($text);
187:        $blocks = array_reverse($this->_blocks);
188:        
189:        foreach ($blocks as $blockKey => $blockValue) {
190:            $text = str_replace($blockKey, $blockValue, $text);
191:        }
192:        
193:        return $this->fixPragraph($text);        
194:    }
danger parse preg_replace_callback第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
132:    public function parse($text)
133:    {
134:        /** 重置计数器 */
135:        $this->_uniqueId = 0;
136:        $this->_blocks = array();
137:        
138:        /** 将已有的段落后面的换行处理掉 */
139:        $text = preg_replace(array("/<\/p>\s+<p(\s*)/is", "/\s*<br\s*\/?>\s*/is"), array("</p><p\\1", "<br />"), trim($text));
140:        
141:        /** 将所有非自闭合标签解析为唯一的字符串 */
142:        $foundTagCount = 0;
143:        $textLength = strlen($text);
144:        $uniqueIdList = array();
145:
146:        if (preg_match_all("/<\/\s*([a-z0-9]+)>/is", $text, $matches, PREG_OFFSET_CAPTURE)) {
147:            foreach ($matches[0] as $key => $match) {
148:                $tag = $matches[1][$key][0];
149:                
150:                $leftOffset = $match[1] - $textLength;
151:                $posSingle = strrpos($text, '<' . $tag . '>', $leftOffset);
152:                $posFix = strrpos($text, '<' . $tag . ' ', $leftOffset);
153:                $pos = false;
154:                
155:                switch (true) {
156:                    case (false !== $posSingle && false !== $posFix):
157:                        $pos = max($posSingle, $posFix);
158:                        break;
159:                    case false === $posSingle && false !== $posFix:
160:                        $pos = $posFix;
161:                        break;
162:                    case false !== $posSingle && false === $posFix:
163:                        $pos = $posSingle;
164:                        break;
165:                    default:
166:                        break;
167:                }
168:                
169:                if (false !== $pos) {
170:                    $uniqueId = $this->makeUniqueId();
171:                    $uniqueIdList[$uniqueId] = $tag;
172:                    $tagLength = strlen($tag);
173:                    
174:                    $text = substr_replace($text, $uniqueId, $pos + 1 + $tagLength, 0);
175:                    $text = substr_replace($text, $uniqueId, $match[1] + 7 + $foundTagCount * 10 + $tagLength, 0); // 7 = 5 + 2
176:                    $foundTagCount ++;
177:                }
178:            }
179:        }
180:        
181:        foreach ($uniqueIdList as $uniqueId => $tag) {
182:            $text = preg_replace_callback("/<({$tag})({$uniqueId})([^>]*)>(.*)<\/\\1\\2>/is",
183:                array($this, 'replaceBlockCallback'), $text, 1);
184:        }
185:        
186:        $text = $this->cutByBlock($text);
187:        $blocks = array_reverse($this->_blocks);
188:        
189:        foreach ($blocks as $blockKey => $blockValue) {
190:            $text = str_replace($blockKey, $blockValue, $text);
191:        }
192:        
193:        return $this->fixPragraph($text);        
194:    }

./typecho/var/Typecho/Db/Query.php

等级 函数 说明
danger quoteValues array_map第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
193:    protected function quoteValues(array $values)
194:    {
195:        foreach ($values as &$value) {
196:            if (is_array($value)) {
197:                $value = '(' . implode(',', array_map(array($this, 'quoteValue'), $value)) . ')';
198:            } else {
199:                $value = $this->quoteValue($value);
200:            }
201:        }
202:
203:        return $values;
204:    }

./typecho/var/Typecho/Router.php

等级 函数 说明
danger dispatch 动态调用方法,可能存在远程代码执行的隐患
代码
117:    public static function dispatch()
118:    {
119:        /** 获取PATHINFO */
120:        $pathInfo = self::getPathInfo();
121:
122:        foreach (self::$_routingTable as $key => $route) {
123:            if (preg_match($route['regx'], $pathInfo, $matches)) {
124:                self::$current = $key;
125:
126:                try {
127:                    /** 载入参数 */
128:                    $params = NULL;
129:
130:                    if (!empty($route['params'])) {
131:                        unset($matches[0]);
132:                        $params = array_combine($route['params'], $matches);
133:                    }
134:
135:                    $widget = Typecho_Widget::widget($route['widget'], NULL, $params);
136:
137:                    if (isset($route['action'])) {
138:                        $widget->{$route['action']}();
139:                    }
140:
141:                    return;
142:
143:                } catch (Exception $e) {
144:                    if (404 == $e->getCode()) {
145:                        Typecho_Widget::destory($route['widget']);
146:                        continue;
147:                    }
148:
149:                    throw $e;
150:                }
151:            }
152:        }
153:
154:        /** 载入路由异常支持 */
155:        throw new Typecho_Router_Exception("Path '{$pathInfo}' not found", 404);
156:    }

./typecho/var/Typecho/Validate.php

等级 函数 说明
danger run call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
101:    public function run(array $data, $rules = NULL)
102:    {
103:        $result = array();
104:        $this->_data = $data;
105:        $rules = empty($rules) ? $this->_rules : $rules;
106:
107:        // Cycle through the rules and test for errors
108:        foreach ($rules as $key => $rules) {
109:            $this->_key = $key;
110:            $data[$key] = (is_array($data[$key]) ? 0 == count($data[$key])
111:                : 0 == strlen($data[$key])) ? NULL : $data[$key];
112:
113:            foreach ($rules as $params) {
114:                $method = $params[0];
115:
116:                if ('required' != $method && 'confirm' != $method && 0 == strlen($data[$key])) {
117:                    continue;
118:                }
119:
120:                $message = $params[1];
121:                $params[1] = $data[$key];
122:                $params = array_slice($params, 1);
123:
124:                if (!call_user_func_array(is_array($method) ? $method : array($this, $method), $params)) {
125:                    $result[$key] = $message;
126:                    break;
127:                }
128:            }
129:
130:            /** 开启中断 */
131:            if ($this->_break && $result) {
132:                break;
133:            }
134:        }
135:
136:        return $result;
137:    }
danger xssCheck preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
277:    public static function xssCheck($str)
278:    {
279:        $search = 'abcdefghijklmnopqrstuvwxyz';
280:        $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
281:        $search .= '1234567890!@#$%^&*()';
282:        $search .= '~`";:?+/={}[]-_|\'\\';
283:
284:        for ($i = 0; $i < strlen($search); $i++) {
285:            // ;? matches the ;, which is optional
286:            // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
287:
288:            // &#x0040 @ search for the hex values
289:            $str = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $str); // with a ;
290:            // &#00064 @ 0{0,7} matches '0' zero to seven times
291:            $str = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $str); // with a ;
292:        }
293:
294:        return !preg_match('/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19]|' . "\r|\n|\t" . ')/', $str);
295:    }
danger xssCheck preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
277:    public static function xssCheck($str)
278:    {
279:        $search = 'abcdefghijklmnopqrstuvwxyz';
280:        $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
281:        $search .= '1234567890!@#$%^&*()';
282:        $search .= '~`";:?+/={}[]-_|\'\\';
283:
284:        for ($i = 0; $i < strlen($search); $i++) {
285:            // ;? matches the ;, which is optional
286:            // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
287:
288:            // &#x0040 @ search for the hex values
289:            $str = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $str); // with a ;
290:            // &#00064 @ 0{0,7} matches '0' zero to seven times
291:            $str = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $str); // with a ;
292:        }
293:
294:        return !preg_match('/(\(|\)|\\\|"|<|>|[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19]|' . "\r|\n|\t" . ')/', $str);
295:    }

./typecho/var/Typecho/Common.php

等级 函数 说明
danger __removeUrlXss preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
70:    public static function __removeUrlXss($string)
71:    {
72:        $string = str_replace(array('%0d', '%0a'), '', strip_tags($string));
73:        return preg_replace(array(
74:            "/\(\s*(\"|')/i",           //函数开头
75:            "/(\"|')\s*\)/i",           //函数结尾
76:        ), '', $string);
77:    }
warning init spl_autoload_register第0个参数,请使用闭包函数
代码
202:    public static function init()
203:    {
204:        /** 设置自动载入函数 */
205:        spl_autoload_register(array('Typecho_Common', '__autoLoad'));
206:
207:        /** 兼容php6 */
208:        if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
209:            $_GET = self::stripslashesDeep($_GET);
210:            $_POST = self::stripslashesDeep($_POST);
211:            $_COOKIE = self::stripslashesDeep($_COOKIE);
212:
213:            reset($_GET);
214:            reset($_POST);
215:            reset($_COOKIE);
216:        }
217:
218:        /** 设置异常截获函数 */
219:        set_exception_handler(array('Typecho_Common', 'exceptionHandle'));
220:    }
warning init set_exception_handler第0个参数,请使用闭包函数
代码
202:    public static function init()
203:    {
204:        /** 设置自动载入函数 */
205:        spl_autoload_register(array('Typecho_Common', '__autoLoad'));
206:
207:        /** 兼容php6 */
208:        if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
209:            $_GET = self::stripslashesDeep($_GET);
210:            $_POST = self::stripslashesDeep($_POST);
211:            $_COOKIE = self::stripslashesDeep($_COOKIE);
212:
213:            reset($_GET);
214:            reset($_POST);
215:            reset($_COOKIE);
216:        }
217:
218:        /** 设置异常截获函数 */
219:        set_exception_handler(array('Typecho_Common', 'exceptionHandle'));
220:    }
warning exceptionHandle 动态创建类对象,可能存在远程代码执行的隐患
代码
229:    public static function exceptionHandle($exception)
230:    {
231:        if (defined('__TYPECHO_DEBUG__')) {
232:            echo '<pre><code>';
233:            echo '<h1>' . htmlspecialchars($exception->getMessage()) . '</h1>';
234:            echo htmlspecialchars($exception->__toString());
235:            echo '</code></pre>';
236:        } else {
237:            @ob_end_clean();
238:            if (404 == $exception->getCode() && !empty(self::$exceptionHandle)) {
239:                $handleClass = self::$exceptionHandle;
240:                new $handleClass($exception);
241:            } else {
242:                self::error($exception);
243:            }
244:        }
245:
246:        exit;
247:    }
danger error 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
256:    public static function error($exception)
257:    {
258:        $isException = is_object($exception);
259:        $message = '';
260:
261:        if ($isException) {
262:            $code = $exception->getCode();
263:            $message = $exception->getMessage();
264:        } else {
265:            $code = $exception;
266:        }
267:
268:        $charset = self::$charset;
269:
270:        if ($isException && $exception instanceof Typecho_Db_Exception) {
271:            $code = 500;
272:            @error_log($message);
273:
274:            //覆盖原始错误信息
275:            $message = 'Database Server Error';
276:
277:            if ($exception instanceof Typecho_Db_Adapter_Exception) {
278:                $code = 503;
279:                $message = 'Error establishing a database connection';
280:            } else if ($exception instanceof Typecho_Db_Query_Exception) {
281:                $message = 'Database Query Error';
282:            }
283:        } else {
284:            switch ($code) {
285:                case 500:
286:                    $message = 'Server Error';
287:                    break;
288:
289:                case 404:
290:                    $message = 'Page Not Found';
291:                    break;
292:
293:                default:
294:                    $code = 'Error';
295:                    break;
296:            }
297:        }
298:
299:
300:        /** 设置http code */
301:        if (is_numeric($code) && $code > 200) {
302:            Typecho_Response::setStatus($code);
303:        }
304:
305:        $message = nl2br($message);
306:
307:        if (defined('__TYPECHO_EXCEPTION_FILE__')) {
308:            require_once __TYPECHO_EXCEPTION_FILE__;
309:        } else {
310:            echo
311:<<<EOF
312:<!DOCTYPE html>
313:<html lang="en">
314:    <head>
315:        <meta charset="{$charset}">
316:        <title>{$code}</title>
317:        <style>
318:            html {
319:                padding: 50px 10px;
320:                font-size: 16px;
321:                line-height: 1.4;
322:                color: #666;
323:                background: #F6F6F3;
324:                -webkit-text-size-adjust: 100%;
325:                -ms-text-size-adjust: 100%;
326:            }
327:
328:            html,
329:            input { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; }
330:            body {
331:                max-width: 500px;
332:                _width: 500px;
333:                padding: 30px 20px;
334:                margin: 0 auto;
335:                background: #FFF;
336:            }
337:            ul {
338:                padding: 0 0 0 40px;
339:            }
340:            .container {
341:                max-width: 380px;
342:                _width: 380px;
343:                margin: 0 auto;
344:            }
345:        </style>
346:    </head>
347:    <body>
348:        <div class="container">
349:            {$message}
350:        </div>
351:    </body>
352:</html>
353:EOF;
354:        }
355:
356:        exit;
357:    }
warning isAvailableClass array_filter第1个参数,请使用闭包函数
代码
372:    public static function isAvailableClass($className, $path = NULL)
373:    {
374:        /** 获取所有include目录 */
375:        //增加安全目录检测 fix issue 106
376:        $dirs = array_map('realpath', array_filter(explode(PATH_SEPARATOR, get_include_path()),
377:        array('Typecho_Common', '__safePath')));
378:
379:        $file = str_replace('_', '/', $className) . '.php';
380:
381:        if (!empty($path)) {
382:            $path = realpath($path);
383:            if (in_array($path, $dirs)) {
384:                $dirs = array($path);
385:            } else {
386:                return false;
387:            }
388:        }
389:
390:        foreach ($dirs as $dir) {
391:            if (!empty($dir)) {
392:                if (file_exists($dir . '/' . $file)) {
393:                    return true;
394:                }
395:            }
396:        }
397:
398:        return false;
399:    }
warning stripslashesDeep array_map第0个参数,请使用闭包函数
代码
425:    public static function stripslashesDeep($value)
426:    {
427:        return is_array($value) ? array_map(array('Typecho_Common', 'stripslashesDeep'), $value) : stripslashes($value);
428:    }
warning stripTags preg_replace_callback第1个参数,请使用闭包函数
代码
574:    public static function stripTags($html, $allowableTags = NULL)
575:    {
576:        $normalizeTags = '';
577:        $allowableAttributes = array();
578:
579:        if (!empty($allowableTags) && preg_match_all("/\<([_a-z0-9-]+)([^>]*)\>/is", $allowableTags, $tags)) {
580:            $normalizeTags = '<' . implode('><', array_map('strtolower', $tags[1])) . '>';
581:            $attributes = array_map('trim', $tags[2]);
582:            foreach ($attributes as $key => $val) {
583:                $allowableAttributes[strtolower($tags[1][$key])] = 
584:                    array_map('strtolower', array_keys(self::__parseAttrs($val)));
585:            }
586:        }
587:
588:        self::$_allowableAttributes = $allowableAttributes;
589:        $html = strip_tags($html, $normalizeTags);
590:        $html = preg_replace_callback("/<([_a-z0-9-]+)(\s+[^>]+)?>/is",
591:            array('Typecho_Common', '__filterAttrs'), $html);
592:
593:        return $html;
594:    }
warning safeUrl array_map第0个参数,请使用闭包函数
代码
614:    public static function safeUrl($url)
615:    {
616:        //~ 针对location的xss过滤, 因为其特殊性无法使用removeXSS函数
617:        //~ fix issue 66
618:        $params = parse_url(str_replace(array("\r", "\n", "\t", ' '), '', $url));
619:
620:        /** 禁止非法的协议跳转 */
621:        if (isset($params['scheme'])) {
622:            if (!in_array($params['scheme'], array('http', 'https'))) {
623:                return '/';
624:            }
625:        }
626:
627:        /** 过滤解析串 */
628:        $params = array_map(array('Typecho_Common', '__removeUrlXss'), $params);
629:        return self::buildUrl($params);
630:    }
danger removeXSS preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
641:    public static function removeXSS($val)
642:    {
643:       // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
644:       // this prevents some character re-spacing such as <java\0script>
645:       // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
646:       $val = preg_replace('/([\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', '', $val);
647:
648:       // straight replacements, the user should never need these since they're normal characters
649:       // this prevents like <IMG SRC=&#X40&#X61&#X76&#X61&#X73&#X63&#X72&#X69&#X70&#X74&#X3A&#X61&#X6C&#X65&#X72&#X74&#X28&#X27&#X58&#X53&#X53&#X27&#X29>
650:       $search = 'abcdefghijklmnopqrstuvwxyz';
651:       $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
652:       $search .= '1234567890!@#$%^&*()';
653:       $search .= '~`";:?+/={}[]-_|\'\\';
654:
655:       for ($i = 0; $i < strlen($search); $i++) {
656:          // ;? matches the ;, which is optional
657:          // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
658:
659:          // &#x0040 @ search for the hex values
660:          $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
661:          // &#00064 @ 0{0,7} matches '0' zero to seven times
662:          $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
663:       }
664:
665:       // now the only remaining whitespace attacks are \t, \n, and \r
666:       $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
667:       $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
668:       $ra = array_merge($ra1, $ra2);
669:
670:       $found = true; // keep replacing as long as the previous round replaced something
671:       while ($found == true) {
672:          $val_before = $val;
673:          for ($i = 0; $i < sizeof($ra); $i++) {
674:             $pattern = '/';
675:             for ($j = 0; $j < strlen($ra[$i]); $j++) {
676:                if ($j > 0) {
677:                   $pattern .= '(';
678:                   $pattern .= '(&#[xX]0{0,8}([9ab]);)';
679:                   $pattern .= '|';
680:                   $pattern .= '|(&#0{0,8}([9|10|13]);)';
681:                   $pattern .= ')*';
682:                }
683:                $pattern .= $ra[$i][$j];
684:             }
685:             $pattern .= '/i';
686:             $replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
687:             $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
688:
689:             if ($val_before == $val) {
690:                // no replacements were made, so exit the loop
691:                $found = false;
692:             }
693:          }
694:       }
695:
696:       return $val;
697:    }
danger removeXSS preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
641:    public static function removeXSS($val)
642:    {
643:       // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
644:       // this prevents some character re-spacing such as <java\0script>
645:       // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
646:       $val = preg_replace('/([\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', '', $val);
647:
648:       // straight replacements, the user should never need these since they're normal characters
649:       // this prevents like <IMG SRC=&#X40&#X61&#X76&#X61&#X73&#X63&#X72&#X69&#X70&#X74&#X3A&#X61&#X6C&#X65&#X72&#X74&#X28&#X27&#X58&#X53&#X53&#X27&#X29>
650:       $search = 'abcdefghijklmnopqrstuvwxyz';
651:       $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
652:       $search .= '1234567890!@#$%^&*()';
653:       $search .= '~`";:?+/={}[]-_|\'\\';
654:
655:       for ($i = 0; $i < strlen($search); $i++) {
656:          // ;? matches the ;, which is optional
657:          // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
658:
659:          // &#x0040 @ search for the hex values
660:          $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
661:          // &#00064 @ 0{0,7} matches '0' zero to seven times
662:          $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
663:       }
664:
665:       // now the only remaining whitespace attacks are \t, \n, and \r
666:       $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
667:       $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
668:       $ra = array_merge($ra1, $ra2);
669:
670:       $found = true; // keep replacing as long as the previous round replaced something
671:       while ($found == true) {
672:          $val_before = $val;
673:          for ($i = 0; $i < sizeof($ra); $i++) {
674:             $pattern = '/';
675:             for ($j = 0; $j < strlen($ra[$i]); $j++) {
676:                if ($j > 0) {
677:                   $pattern .= '(';
678:                   $pattern .= '(&#[xX]0{0,8}([9ab]);)';
679:                   $pattern .= '|';
680:                   $pattern .= '|(&#0{0,8}([9|10|13]);)';
681:                   $pattern .= ')*';
682:                }
683:                $pattern .= $ra[$i][$j];
684:             }
685:             $pattern .= '/i';
686:             $replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
687:             $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
688:
689:             if ($val_before == $val) {
690:                // no replacements were made, so exit the loop
691:                $found = false;
692:             }
693:          }
694:       }
695:
696:       return $val;
697:    }
danger removeXSS preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
641:    public static function removeXSS($val)
642:    {
643:       // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
644:       // this prevents some character re-spacing such as <java\0script>
645:       // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
646:       $val = preg_replace('/([\x00-\x08]|[\x0b-\x0c]|[\x0e-\x19])/', '', $val);
647:
648:       // straight replacements, the user should never need these since they're normal characters
649:       // this prevents like <IMG SRC=&#X40&#X61&#X76&#X61&#X73&#X63&#X72&#X69&#X70&#X74&#X3A&#X61&#X6C&#X65&#X72&#X74&#X28&#X27&#X58&#X53&#X53&#X27&#X29>
650:       $search = 'abcdefghijklmnopqrstuvwxyz';
651:       $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
652:       $search .= '1234567890!@#$%^&*()';
653:       $search .= '~`";:?+/={}[]-_|\'\\';
654:
655:       for ($i = 0; $i < strlen($search); $i++) {
656:          // ;? matches the ;, which is optional
657:          // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
658:
659:          // &#x0040 @ search for the hex values
660:          $val = preg_replace('/(&#[xX]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
661:          // &#00064 @ 0{0,7} matches '0' zero to seven times
662:          $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
663:       }
664:
665:       // now the only remaining whitespace attacks are \t, \n, and \r
666:       $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'style', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
667:       $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
668:       $ra = array_merge($ra1, $ra2);
669:
670:       $found = true; // keep replacing as long as the previous round replaced something
671:       while ($found == true) {
672:          $val_before = $val;
673:          for ($i = 0; $i < sizeof($ra); $i++) {
674:             $pattern = '/';
675:             for ($j = 0; $j < strlen($ra[$i]); $j++) {
676:                if ($j > 0) {
677:                   $pattern .= '(';
678:                   $pattern .= '(&#[xX]0{0,8}([9ab]);)';
679:                   $pattern .= '|';
680:                   $pattern .= '|(&#0{0,8}([9|10|13]);)';
681:                   $pattern .= ')*';
682:                }
683:                $pattern .= $ra[$i][$j];
684:             }
685:             $pattern .= '/i';
686:             $replacement = substr($ra[$i], 0, 2).'<x>'.substr($ra[$i], 2); // add in <> to nerf the tag
687:             $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
688:
689:             if ($val_before == $val) {
690:                // no replacements were made, so exit the loop
691:                $found = false;
692:             }
693:          }
694:       }
695:
696:       return $val;
697:    }
warning strToUpper preg_replace_callback第1个参数,请使用闭包函数
代码
757:    public static function strToUpper($str)
758:    {
759:        if (__TYPECHO_MB_SUPPORTED__) {
760:            return mb_strtoupper($str, self::$charset);
761:        } else {
762:            return 'UTF-8' == strtoupper(self::$charset)
763:                ? preg_replace_callback("/[a-z]+/u", array('Typecho_Common', '__strToUpper'), $str) : strtoupper($str);
764:        }
765:    }
warning checkStrEncoding array_map第0个参数,请使用闭包函数
代码
773:    public static function checkStrEncoding($str)
774:    {
775:        if (is_array($str)) {
776:            return array_map(array('Typecho_Common', 'checkStrEncoding'), $str);
777:        }
778:
779:        if (__TYPECHO_MB_SUPPORTED__) {
780:            return mb_check_encoding($str, self::$charset);
781:        } else {
782:            // just support utf-8
783:            return preg_match('//u', $str);
784:        }
785:    }

./typecho/var/Typecho/I18n/GetText.php

等级 函数 说明
critical select_string eval参数包含动态变量或函数,可能有远程代码执行的隐患
代码
322:    private function select_string($n)
323:    {
324:        $string = $this->get_plural_forms();
325:        $string = str_replace('nplurals',"\$total",$string);
326:        $string = str_replace("n",$n,$string);
327:        $string = str_replace('plural',"\$plural",$string);
328:
329:        $total = 0;
330:        $plural = 0;
331:
332:        eval("$string");
333:        if ($plural >= $total) $plural = $total - 1;
334:        return $plural;
335:    }

./typecho/var/Typecho/Widget.php

等级 函数 说明
warning widget 动态创建类对象,可能存在远程代码执行的隐患
代码
190:    public static function widget($alias, $params = NULL, $request = NULL, $enableResponse = true)
191:    {
192:        $parts = explode('@', $alias);
193:        $className = $parts[0];
194:        $alias = empty($parts[1]) ? $className : $parts[1];
195:
196:        if (isset(self::$_widgetAlias[$className])) {
197:            $className = self::$_widgetAlias[$className];
198:        }
199:
200:        if (!isset(self::$_widgetPool[$alias])) {
201:            /** 如果类不存在 */
202:            if (!class_exists($className)) {
203:                throw new Typecho_Widget_Exception($className);
204:            }
205:
206:            /** 初始化request */
207:            if (!empty($request)) {
208:                $requestObject = new Typecho_Request();
209:                $requestObject->setParams($request);
210:            } else {
211:                $requestObject = Typecho_Request::getInstance();
212:            }
213:
214:            /** 初始化response */
215:            $responseObject = $enableResponse ? Typecho_Response::getInstance()
216:            : Typecho_Widget_Helper_Empty::getInstance();
217:
218:            /** 初始化组件 */
219:            $widget = new $className($requestObject, $responseObject, $params);
220:
221:            $widget->execute();
222:            self::$_widgetPool[$alias] = $widget;
223:        }
224:
225:        return self::$_widgetPool[$alias];
226:    }
danger parse preg_replace_callback第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
259:    public function parse($format)
260:    {
261:        while ($this->next()) {
262:            echo preg_replace_callback("/\{([_a-z0-9]+)\}/i", 
263:                array($this, '__parseCallback'), $format);
264:        }
265:    }
danger __call 动态调用方法,可能存在远程代码执行的隐患
代码
363:    public function __call($name, $args)
364:    {
365:        $method = 'call' . ucfirst($name);
366:        $this->pluginHandle()->trigger($plugged)->{$method}($this, $args);
367:
368:        if (!$plugged) {
369:            echo $this->{$name};
370:        }
371:    }
danger __get 动态调用方法,可能存在远程代码执行的隐患
代码
380:    public function __get($name)
381:    {
382:        if (array_key_exists($name, $this->row)) {
383:            return $this->row[$name];
384:        } else {
385:            $method = '___' . $name;
386:
387:            if (method_exists($this, $method)) {
388:                return $this->$method();
389:            } else {
390:                $return = $this->pluginHandle()->trigger($plugged)->{$method}($this);
391:                if ($plugged) {
392:                    return $return;
393:                }
394:            }
395:        }
396:
397:        return NULL;
398:    }
danger __get 动态调用方法,可能存在远程代码执行的隐患
代码
380:    public function __get($name)
381:    {
382:        if (array_key_exists($name, $this->row)) {
383:            return $this->row[$name];
384:        } else {
385:            $method = '___' . $name;
386:
387:            if (method_exists($this, $method)) {
388:                return $this->$method();
389:            } else {
390:                $return = $this->pluginHandle()->trigger($plugged)->{$method}($this);
391:                if ($plugged) {
392:                    return $return;
393:                }
394:            }
395:        }
396:
397:        return NULL;
398:    }

./typecho/var/Typecho/Router/Parser.php

等级 函数 说明
danger parse preg_replace_callback第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
96:    public function parse()
97:    {
98:        $result = array();
99:
100:        foreach ($this->_routingTable as $key => $route) {
101:            $this->_params = array();
102:            $route['regx'] = preg_replace_callback("/%([^%]+)%/", array($this, '_match'),
103:            preg_quote(str_replace(array('[', ']', ':'), array('%', '%', ' '), $route['url'])));
104:
105:            /** 处理斜线 */
106:            $route['regx'] = rtrim($route['regx'], '/');
107:            $route['regx'] = '|^' . $route['regx'] . '[/]?$|';
108:
109:            $route['format'] = preg_replace("/\[([^\]]+)\]/", "%s", $route['url']);
110:            $route['params'] = $this->_params;
111:
112:            $result[$key] = $route;
113:        }
114:
115:        return $result;
116:    }

./typecho/var/Markdown.php

等级 函数 说明
warning transerComment preg_replace_callback第1个参数,请使用闭包函数
代码
64:    public static function transerComment($html)
65:    {
66:        return preg_replace_callback("/<!\-\-(.+?)\-\->/s", array('Markdown', 'transerCommentCallback'), $html);
67:    }

./typecho/var/Widget/Abstract/Contents.php

等级 函数 说明
danger ___tags fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
24:    protected function ___tags()
25:    {
26:        return $this->db->fetchAll($this->db
27:        ->select()->from('table.metas')
28:        ->join('table.relationships', 'table.relationships.mid = table.metas.mid')
29:        ->where('table.relationships.cid = ?', $this->cid)
30:        ->where('table.metas.type = ?', 'tag'), array($this->widget('Widget_Abstract_Metas'), 'filter'));
31:    }
danger filter fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
633:    public function filter(array $value)
634:    {
635:        /** 取出所有分类 */
636:        $value['categories'] = $this->db->fetchAll($this->db
637:            ->select()->from('table.metas')
638:            ->join('table.relationships', 'table.relationships.mid = table.metas.mid')
639:            ->where('table.relationships.cid = ?', $value['cid'])
640:            ->where('table.metas.type = ?', 'category')
641:            ->order('table.metas.order', Typecho_Db::SORT_ASC), array($this->widget('Widget_Metas_Category_List'), 'filter'));
642:        $value['category'] = NULL;
643:        $value['directory'] = array();
644:
645:        /** 取出第一个分类作为slug条件 */
646:        if (!empty($value['categories'])) {
647:            $value['category'] = $value['categories'][0]['slug'];
648:
649:            $value['directory'] = $this->widget('Widget_Metas_Category_List')->getAllParentsSlug($value['categories'][0]['mid']);
650:            $value['directory'][] = $value['category'];
651:        }
652:
653:        $value['date'] = new Typecho_Date($value['created']);
654:
655:        /** 生成日期 */
656:        $value['year'] = $value['date']->year;
657:        $value['month'] = $value['date']->month;
658:        $value['day'] = $value['date']->day;
659:
660:        /** 生成访问权限 */
661:        $value['hidden'] = false;
662:
663:        /** 获取路由类型并判断此类型在路由表中是否存在 */
664:        $type = $value['type'];
665:        $routeExists = (NULL != Typecho_Router::get($type));
666:
667:        $tmpSlug = $value['slug'];
668:        $tmpCategory = $value['category'];
669:        $tmpDirectory = $value['directory'];
670:        $value['slug'] = urlencode($value['slug']);
671:        $value['category'] = urlencode($value['category']);
672:        $value['directory'] = implode('/', array_map('urlencode', $value['directory']));
673:
674:        /** 生成静态路径 */
675:        $value['pathinfo'] = $routeExists ? Typecho_Router::url($type, $value) : '#';
676:
677:        /** 生成静态链接 */
678:        $value['permalink'] = Typecho_Common::url($value['pathinfo'], $this->options->index);
679:
680:        /** 处理附件 */
681:        if ('attachment' == $type) {
682:            $content = @unserialize($value['text']);
683:
684:            //增加数据信息
685:            $value['attachment'] = new Typecho_Config($content);
686:            $value['attachment']->isImage = in_array($content['type'], array('jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp'));
687:            $value['attachment']->url = Widget_Upload::attachmentHandle($value);
688:
689:            if ($value['attachment']->isImage) {
690:                $value['text'] = '<img src="' . $value['attachment']->url . '" alt="' .
691:                $value['title'] . '" />';
692:            } else {
693:                $value['text'] = '<a href="' . $value['attachment']->url . '" title="' .
694:                $value['title'] . '">' . $value['title'] . '</a>';
695:            }
696:        }
697:
698:        /** 处理Markdown **/
699:        if (isset($value['text'])) {
700:            $value['isMarkdown'] = (0 === strpos($value['text'], '<!--markdown-->'));
701:            if ($value['isMarkdown']) {
702:                $value['text'] = substr($value['text'], 15);
703:            }
704:        }
705:
706:        /** 生成聚合链接 */
707:        /** RSS 2.0 */
708:        $value['feedUrl'] = $routeExists ? Typecho_Router::url($type, $value, $this->options->feedUrl) : '#';
709:
710:        /** RSS 1.0 */
711:        $value['feedRssUrl'] = $routeExists ? Typecho_Router::url($type, $value, $this->options->feedRssUrl) : '#';
712:
713:        /** ATOM 1.0 */
714:        $value['feedAtomUrl'] = $routeExists ? Typecho_Router::url($type, $value, $this->options->feedAtomUrl) : '#';
715:
716:        $value['slug'] = $tmpSlug;
717:        $value['category'] = $tmpCategory;
718:        $value['directory'] = $tmpDirectory;
719:        
720:        /** 处理密码保护流程 */
721:        if (!empty($value['password']) &&
722:        $value['password'] !== Typecho_Cookie::get('protectPassword') &&
723:        $value['authorId'] != $this->user->uid && 
724:        !$this->user->pass('editor', true)) {
725:            $value['hidden'] = true;
726:
727:            /** 抛出错误 */
728:            if ($this->request->isPost() && isset($this->request->protectPassword)) {
729:                throw new Typecho_Widget_Exception(_t('对不起,您输入的密码错误'), 403);
730:            }
731:        }
732:
733:        $value = $this->pluginHandle(__CLASS__)->filter($value, $this);
734:
735:        /** 如果访问权限被禁止 */
736:        if ($value['hidden']) {
737:            $value['text'] = '<form class="protected" action="' . $this->security->getTokenUrl($value['permalink'])
738:                . '" method="post">' .
739:            '<p class="word">' . _t('请输入密码访问') . '</p>' .
740:            '<p><input type="password" class="text" name="protectPassword" />
741:            <input type="submit" class="submit" value="' . _t('提交') . '" /></p>' .
742:            '</form>';
743:
744:            $value['title'] = _t('此内容被密码保护');
745:            $value['tags'] = array();
746:            $value['commentsNum'] = 0;
747:        }
748:
749:        return $value;
750:    }

./typecho/var/Widget/Options/General.php

等级 函数 说明
danger updateGeneralSettings array_filter第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
207:    public function updateGeneralSettings()
208:    {
209:        /** 验证格式 */
210:        if ($this->form()->validate()) {
211:            $this->response->goBack();
212:        }
213:
214:        $settings = $this->request->from('title','description', 'keywords', 'allowRegister', 'lang', 'timezone');
215:        $settings['attachmentTypes'] = $this->request->getArray('attachmentTypes');
216:
217:        if (!defined('__TYPECHO_SITE_URL__')) {
218:            $settings['siteUrl'] = rtrim($this->request->siteUrl, '/');
219:        }
220:
221:        $attachmentTypes = array();
222:        if ($this->isEnableByCheckbox($settings['attachmentTypes'], '@image@')) {
223:            $attachmentTypes[] = '@image@';
224:        }
225:        
226:        if ($this->isEnableByCheckbox($settings['attachmentTypes'], '@media@')) {
227:            $attachmentTypes[] = '@media@';
228:        }
229:        
230:        if ($this->isEnableByCheckbox($settings['attachmentTypes'], '@doc@')) {
231:            $attachmentTypes[] = '@doc@';
232:        }
233:        
234:        $attachmentTypesOther = $this->request->filter('trim', 'strtolower')->attachmentTypesOther;
235:        if ($this->isEnableByCheckbox($settings['attachmentTypes'], '@other@') && !empty($attachmentTypesOther)) {
236:            $types = implode(',', array_filter(array_map('trim',
237:                explode(',', $attachmentTypesOther)), array($this, 'removeShell')));
238:
239:            if (!empty($types)) {
240:                $attachmentTypes[] = $types;
241:            }
242:        }
243:        
244:        $settings['attachmentTypes'] = implode(',', $attachmentTypes);
245:        foreach ($settings as $name => $value) {
246:            $this->update(array('value' => $value), $this->db->sql()->where('name = ?', $name));
247:        }
248:
249:        $this->widget('Widget_Notice')->set(_t("设置已经保存"), 'success');
250:        $this->response->goBack();
251:    }

./typecho/var/Widget/Comments/Archive.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
208:    public function execute()
209:    {
210:        if (!$this->parameter->parentId) {
211:            return;
212:        }
213:
214:        $commentsAuthor = Typecho_Cookie::get('__typecho_remember_author');
215:        $commentsMail = Typecho_Cookie::get('__typecho_remember_mail');
216:        $select = $this->select()->where('table.comments.cid = ?', $this->parameter->parentId)
217:        ->where('table.comments.status = ? OR (table.comments.author = ? AND table.comments.mail = ? AND table.comments.status = ?)', 'approved', $commentsAuthor, $commentsMail, 'waiting');
218:        $threadedSelect = NULL;
219:        
220:        if ($this->options->commentsShowCommentOnly) {
221:            $select->where('table.comments.type = ?', 'comment');
222:        }
223:        
224:        $select->order('table.comments.coid', 'ASC');
225:        $this->db->fetchAll($select, array($this, 'push'));
226:        
227:        /** 需要输出的评论列表 */
228:        $outputComments = array();
229:        
230:        /** 如果开启评论回复 */
231:        if ($this->options->commentsThreaded) {
232:        
233:            foreach ($this->stack as $coid => &$comment) {
234:                
235:                /** 取出父节点 */
236:                $parent = $comment['parent'];
237:            
238:                /** 如果存在父节点 */
239:                if (0 != $parent && isset($this->stack[$parent])) {
240:                
241:                    /** 如果当前节点深度大于最大深度, 则将其挂接在父节点上 */
242:                    if ($comment['levels'] >= $this->options->commentsMaxNestingLevels) {
243:                        $comment['levels'] = $this->stack[$parent]['levels'];
244:                        $parent = $this->stack[$parent]['parent'];     // 上上层节点
245:                        $comment['parent'] = $parent;
246:                    }
247:                
248:                    /** 计算子节点顺序 */
249:                    $comment['order'] = isset($this->_threadedComments[$parent]) 
250:                        ? count($this->_threadedComments[$parent]) + 1 : 1;
251:                
252:                    /** 如果是子节点 */
253:                    $this->_threadedComments[$parent][$coid] = $comment;
254:                } else {
255:                    $outputComments[$coid] = $comment;
256:                }
257:                
258:            }
259:        
260:            $this->stack = $outputComments;
261:        }
262:        
263:        /** 评论排序 */
264:        if ('DESC' == $this->options->commentsOrder) {
265:            $this->stack = array_reverse($this->stack, true);
266:            $this->_threadedComments = array_map('array_reverse', $this->_threadedComments);
267:        }
268:        
269:        /** 评论总数 */
270:        $this->_total = count($this->stack);
271:        
272:        /** 对评论进行分页 */
273:        if ($this->options->commentsPageBreak) {
274:            if ('last' == $this->options->commentsPageDisplay && !$this->parameter->commentPage) {
275:                $this->_currentPage = ceil($this->_total / $this->options->commentsPageSize);
276:            } else {
277:                $this->_currentPage = $this->parameter->commentPage ? $this->parameter->commentPage : 1;
278:            }
279:            
280:            /** 截取评论 */
281:            $this->stack = array_slice($this->stack,
282:                ($this->_currentPage - 1) * $this->options->commentsPageSize, $this->options->commentsPageSize);
283:            
284:            /** 评论置位 */
285:            $this->row = current($this->stack);
286:            $this->length = count($this->stack);
287:        }
288:        
289:        reset($this->stack);
290:    }

./typecho/var/Widget/Comments/Recent.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
42:    public function execute()
43:    {
44:        $select  = $this->select()->limit($this->parameter->pageSize)
45:        ->where('table.comments.status = ?', 'approved')
46:        ->order('table.comments.coid', Typecho_Db::SORT_DESC);
47:
48:        if ($this->parameter->parentId) {
49:            $select->where('cid = ?', $this->parameter->parentId);
50:        }
51:
52:        if ($this->options->commentsShowCommentOnly) {
53:            $select->where('type = ?', 'comment');
54:        }
55:        
56:        /** 忽略作者评论 */
57:        if ($this->parameter->ignoreAuthor) {
58:            $select->where('ownerId <> authorId');
59:        }
60:
61:        $this->db->fetchAll($select, array($this, 'push'));
62:    }

./typecho/var/Widget/Comments/Ping.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
117:    public function execute()
118:    {
119:        if (!$this->parameter->parentId) {
120:            return;
121:        }
122:        
123:        $select = $this->select()->where('table.comments.status = ?', 'approved')
124:        ->where('table.comments.cid = ?', $this->parameter->parentId)
125:        ->where('table.comments.type <> ?', 'comment')
126:        ->order('table.comments.coid', 'ASC');
127:
128:        $this->db->fetchAll($select, array($this, 'push'));
129:    }

./typecho/var/Widget/Comments/Admin.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
82:    public function execute()
83:    {
84:        $select = $this->select();
85:        $this->parameter->setDefault('pageSize=20');
86:        $this->_currentPage = $this->request->get('page', 1);
87:
88:        /** 过滤标题 */
89:        if (NULL != ($keywords = $this->request->filter('search')->keywords)) {
90:            $select->where('table.comments.text LIKE ?', '%' . $keywords . '%');
91:        }
92:
93:        /** 如果具有贡献者以上权限,可以查看所有评论,反之只能查看自己的评论 */
94:        if (!$this->user->pass('editor', true)) {
95:            $select->where('table.comments.ownerId = ?', $this->user->uid);
96:        } else if (!isset($this->request->cid)) {
97:            if ('on' == $this->request->__typecho_all_comments) {
98:                Typecho_Cookie::set('__typecho_all_comments', 'on');
99:            } else {
100:                if ('off' == $this->request->__typecho_all_comments) {
101:                    Typecho_Cookie::set('__typecho_all_comments', 'off');
102:                }
103:
104:                if ('on' != Typecho_Cookie::get('__typecho_all_comments')) {
105:                    $select->where('table.comments.ownerId = ?', $this->user->uid);
106:                }
107:            }
108:        }
109:
110:        if (in_array($this->request->status, array('approved', 'waiting', 'spam'))) {
111:            $select->where('table.comments.status = ?', $this->request->status);
112:        } else if ('hold' == $this->request->status) {
113:            $select->where('table.comments.status <> ?', 'approved');
114:        } else {
115:            $select->where('table.comments.status = ?', 'approved');
116:        }
117:
118:        //增加按文章归档功能
119:        if (isset($this->request->cid)) {
120:            $select->where('table.comments.cid = ?', $this->request->filter('int')->cid);
121:        }
122:
123:        $this->_countSql = clone $select;
124:
125:        $select->order('table.comments.coid', Typecho_Db::SORT_DESC)
126:        ->page($this->_currentPage, $this->parameter->pageSize);
127:
128:        $this->db->fetchAll($select, array($this, 'push'));
129:    }

./typecho/var/Widget/Contents/Page/List.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
30:    public function execute()
31:    {
32:        $select = $this->select()->where('table.contents.type = ?', 'page')
33:        ->where('table.contents.status = ?', 'publish')
34:        ->where('table.contents.created < ?', $this->options->gmtTime)
35:        ->order('table.contents.order', Typecho_Db::SORT_ASC);
36:
37:        //去掉自定义首页
38:        $frontPage = explode(':', $this->options->frontPage);
39:        if (2 == count($frontPage) && 'page' == $frontPage[0]) {
40:            $select->where('table.contents.cid <> ?', $frontPage[1]);
41:        }
42:
43:        $this->db->fetchAll($select, array($this, 'push'));
44:    }

./typecho/var/Widget/Contents/Page/Admin.php

等级 函数 说明
danger execute call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
29:    public function execute()
30:    {
31:        /** 过滤状态 */
32:        $select = $this->select()->where('table.contents.type = ? OR (table.contents.type = ? AND table.contents.parent = ?)', 'page', 'page_draft', 0);
33:
34:        /** 过滤标题 */
35:        if (NULL != ($keywords = $this->request->keywords)) {
36:            $args = array();
37:            $keywordsList = explode(' ', $keywords);
38:            $args[] = implode(' OR ', array_fill(0, count($keywordsList), 'table.contents.title LIKE ?'));
39:
40:            foreach ($keywordsList as $keyword) {
41:                $args[] = '%' . Typecho_Common::filterSearchQuery($keyword) . '%';
42:            }
43:
44:            call_user_func_array(array($select, 'where'), $args);
45:        }
46:
47:        /** 提交查询 */
48:        $select->order('table.contents.order', Typecho_Db::SORT_ASC);
49:
50:        $this->db->fetchAll($select, array($this, 'push'));
51:    }
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
29:    public function execute()
30:    {
31:        /** 过滤状态 */
32:        $select = $this->select()->where('table.contents.type = ? OR (table.contents.type = ? AND table.contents.parent = ?)', 'page', 'page_draft', 0);
33:
34:        /** 过滤标题 */
35:        if (NULL != ($keywords = $this->request->keywords)) {
36:            $args = array();
37:            $keywordsList = explode(' ', $keywords);
38:            $args[] = implode(' OR ', array_fill(0, count($keywordsList), 'table.contents.title LIKE ?'));
39:
40:            foreach ($keywordsList as $keyword) {
41:                $args[] = '%' . Typecho_Common::filterSearchQuery($keyword) . '%';
42:            }
43:
44:            call_user_func_array(array($select, 'where'), $args);
45:        }
46:
47:        /** 提交查询 */
48:        $select->order('table.contents.order', Typecho_Db::SORT_ASC);
49:
50:        $this->db->fetchAll($select, array($this, 'push'));
51:    }

./typecho/var/Widget/Contents/Post/Recent.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
29:    public function execute()
30:    {
31:        $this->parameter->setDefault(array('pageSize' => $this->options->postsListSize));
32:
33:        $this->db->fetchAll($this->select()
34:        ->where('table.contents.status = ?', 'publish')
35:        ->where('table.contents.created < ?', $this->options->gmtTime)
36:        ->where('table.contents.type = ?', 'post')
37:        ->order('table.contents.created', Typecho_Db::SORT_DESC)
38:        ->limit($this->parameter->pageSize), array($this, 'push'));
39:    }

./typecho/var/Widget/Contents/Post/Edit.php

等级 函数 说明
danger ___tags fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
38:    protected function ___tags()
39:    {
40:        if ($this->have()) {
41:            return $this->db->fetchAll($this->db
42:            ->select()->from('table.metas')
43:            ->join('table.relationships', 'table.relationships.mid = table.metas.mid')
44:            ->where('table.relationships.cid = ?', $this->cid)
45:            ->where('table.metas.type = ?', 'tag'), array($this->widget('Widget_Abstract_Metas'), 'filter'));
46:        }
47:
48:        return array();
49:    }
danger filter fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
400:    public function filter(array $value)
401:    {
402:        if ('post' == $value['type'] || 'page' == $value['type']) {
403:            $draft = $this->db->fetchRow($this->widget('Widget_Abstract_Contents')->select()
404:            ->where('table.contents.parent = ? AND table.contents.type = ?',
405:                $value['cid'], $value['type'] . '_draft')
406:            ->limit(1));
407:
408:            if (!empty($draft)) {
409:                $draft['slug'] = ltrim($draft['slug'], '@');
410:                $draft['type'] = $value['type'];
411:
412:                $draft = parent::filter($draft);
413:
414:                $draft['tags'] = $this->db->fetchAll($this->db
415:                ->select()->from('table.metas')
416:                ->join('table.relationships', 'table.relationships.mid = table.metas.mid')
417:                ->where('table.relationships.cid = ?', $draft['cid'])
418:                ->where('table.metas.type = ?', 'tag'), array($this->widget('Widget_Abstract_Metas'), 'filter'));
419:                $draft['cid'] = $value['cid'];
420:
421:                return $draft;
422:            }
423:        }
424:
425:        return parent::filter($value);
426:    }
danger getDefaultFieldItems 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
488:    public function getDefaultFieldItems()
489:    {
490:        $defaultFields = array();
491:        $configFile = $this->options->themeFile($this->options->theme, 'functions.php');
492:        $layout = new Typecho_Widget_Helper_Layout();
493:        $fields = new Typecho_Config();
494:
495:        if ($this->have()) {
496:            $fields = $this->fields;
497:        }
498:
499:        $this->pluginHandle()->getDefaultFieldItems($layout);
500:
501:        if (file_exists($configFile)) {
502:            require_once $configFile;
503:            
504:            if (function_exists('themeFields')) {
505:                themeFields($layout); 
506:            }
507:
508:            if (function_exists($this->themeCustomFieldsHook)) {
509:                call_user_func($this->themeCustomFieldsHook, $layout);
510:            }
511:        }
512:
513:        $items = $layout->getItems(); 
514:        foreach ($items as $item) {
515:            if ($item instanceof Typecho_Widget_Helper_Form_Element) {
516:                $name = $item->input->getAttribute('name');
517:
518:                $isFieldReadOnly = $this->pluginHandle('Widget_Abstract_Contents')
519:                    ->trigger($plugged)->isFieldReadOnly($name);
520:                if ($plugged && $isFieldReadOnly) {
521:                    continue;
522:                }
523:
524:                if (preg_match("/^fields\[(.+)\]$/", $name, $matches)) {
525:                    $name = $matches[1];
526:                } else {
527:                    foreach ($item->inputs as $input) {
528:                        $input->setAttribute('name', 'fields[' . $name . ']');
529:                    }
530:                }
531:
532:                $item->value($fields->{$name});
533:
534:                $elements = $item->container->getItems();
535:                array_shift($elements);
536:                $div = new Typecho_Widget_Helper_Layout('div');
537:
538:                foreach ($elements as $el) {
539:                    $div->addItem($el);
540:                }
541:                
542:                $defaultFields[$name] = array($item->label, $div);
543:            }
544:        }
545:
546:        return $defaultFields;
547:    }
danger getDefaultFieldItems call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
488:    public function getDefaultFieldItems()
489:    {
490:        $defaultFields = array();
491:        $configFile = $this->options->themeFile($this->options->theme, 'functions.php');
492:        $layout = new Typecho_Widget_Helper_Layout();
493:        $fields = new Typecho_Config();
494:
495:        if ($this->have()) {
496:            $fields = $this->fields;
497:        }
498:
499:        $this->pluginHandle()->getDefaultFieldItems($layout);
500:
501:        if (file_exists($configFile)) {
502:            require_once $configFile;
503:            
504:            if (function_exists('themeFields')) {
505:                themeFields($layout); 
506:            }
507:
508:            if (function_exists($this->themeCustomFieldsHook)) {
509:                call_user_func($this->themeCustomFieldsHook, $layout);
510:            }
511:        }
512:
513:        $items = $layout->getItems(); 
514:        foreach ($items as $item) {
515:            if ($item instanceof Typecho_Widget_Helper_Form_Element) {
516:                $name = $item->input->getAttribute('name');
517:
518:                $isFieldReadOnly = $this->pluginHandle('Widget_Abstract_Contents')
519:                    ->trigger($plugged)->isFieldReadOnly($name);
520:                if ($plugged && $isFieldReadOnly) {
521:                    continue;
522:                }
523:
524:                if (preg_match("/^fields\[(.+)\]$/", $name, $matches)) {
525:                    $name = $matches[1];
526:                } else {
527:                    foreach ($item->inputs as $input) {
528:                        $input->setAttribute('name', 'fields[' . $name . ']');
529:                    }
530:                }
531:
532:                $item->value($fields->{$name});
533:
534:                $elements = $item->container->getItems();
535:                array_shift($elements);
536:                $div = new Typecho_Widget_Helper_Layout('div');
537:
538:                foreach ($elements as $el) {
539:                    $div->addItem($el);
540:                }
541:                
542:                $defaultFields[$name] = array($item->label, $div);
543:            }
544:        }
545:
546:        return $defaultFields;
547:    }
warning setTags array_filter第1个参数,请使用闭包函数
代码
590:    public function setTags($cid, $tags, $beforeCount = true, $afterCount = true)
591:    {
592:        $tags = str_replace(',', ',', $tags);
593:        $tags = array_unique(array_map('trim', explode(',', $tags)));
594:        $tags = array_filter($tags, array('Typecho_Validate', 'xssCheck'));
595:
596:        /** 取出已有tag */
597:        $existTags = Typecho_Common::arrayFlatten($this->db->fetchAll(
598:        $this->db->select('table.metas.mid')
599:        ->from('table.metas')
600:        ->join('table.relationships', 'table.relationships.mid = table.metas.mid')
601:        ->where('table.relationships.cid = ?', $cid)
602:        ->where('table.metas.type = ?', 'tag')), 'mid');
603:
604:        /** 删除已有tag */
605:        if ($existTags) {
606:            foreach ($existTags as $tag) {
607:                if (0 == strlen($tag)) {
608:                    continue;
609:                }
610:
611:                $this->db->query($this->db->delete('table.relationships')
612:                ->where('cid = ?', $cid)
613:                ->where('mid = ?', $tag));
614:
615:                if ($beforeCount) {
616:                    $this->db->query($this->db->update('table.metas')
617:                    ->expression('count', 'count - 1')
618:                    ->where('mid = ?', $tag));
619:                }
620:            }
621:        }
622:
623:        /** 取出插入tag */
624:        $insertTags = $this->widget('Widget_Abstract_Metas')->scanTags($tags);
625:
626:        /** 插入tag */
627:        if ($insertTags) {
628:            foreach ($insertTags as $tag) {
629:                if (0 == strlen($tag)) {
630:                    continue;
631:                }
632:
633:                $this->db->query($this->db->insert('table.relationships')
634:                ->rows(array(
635:                    'mid'  =>   $tag,
636:                    'cid'  =>   $cid
637:                )));
638:
639:                if ($afterCount) {
640:                    $this->db->query($this->db->update('table.metas')
641:                    ->expression('count', 'count + 1')
642:                    ->where('mid = ?', $tag));
643:                }
644:            }
645:        }
646:    }

./typecho/var/Widget/Contents/Post/Admin.php

等级 函数 说明
danger execute call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
91:    public function execute()
92:    {
93:        $this->parameter->setDefault('pageSize=20');
94:        $this->_currentPage = $this->request->get('page', 1);
95:
96:        /** 构建基础查询 */
97:        $select = $this->select();
98:
99:        /** 如果具有编辑以上权限,可以查看所有文章,反之只能查看自己的文章 */
100:        if (!$this->user->pass('editor', true)) {
101:            $select->where('table.contents.authorId = ?', $this->user->uid);
102:        } else {
103:            if ('on' == $this->request->__typecho_all_posts) {
104:                Typecho_Cookie::set('__typecho_all_posts', 'on');
105:            } else {
106:                if ('off' == $this->request->__typecho_all_posts) {
107:                    Typecho_Cookie::set('__typecho_all_posts', 'off');
108:                }
109:
110:                if ('on' != Typecho_Cookie::get('__typecho_all_posts')) {
111:                    $select->where('table.contents.authorId = ?', isset($this->request->uid) ?
112:                        $this->request->filter('int')->uid : $this->user->uid);
113:                }
114:            }
115:        }
116:
117:        /** 按状态查询 */
118:        if ('draft' == $this->request->status) {
119:            $select->where('table.contents.type = ?', 'post_draft');
120:        } else if ('waiting' == $this->request->status) {
121:            $select->where('(table.contents.type = ? OR table.contents.type = ?) AND table.contents.status = ?',
122:                'post', 'post_draft', 'waiting');
123:        } else {
124:            $select->where('table.contents.type = ? OR (table.contents.type = ? AND table.contents.parent = ?)',
125:                'post', 'post_draft', 0);
126:        }
127:
128:        /** 过滤分类 */
129:        if (NULL != ($category = $this->request->category)) {
130:            $select->join('table.relationships', 'table.contents.cid = table.relationships.cid')
131:            ->where('table.relationships.mid = ?', $category);
132:        }
133:
134:        /** 过滤标题 */
135:        if (NULL != ($keywords = $this->request->filter('search')->keywords)) {
136:            $args = array();
137:            $keywordsList = explode(' ', $keywords);
138:            $args[] = implode(' OR ', array_fill(0, count($keywordsList), 'table.contents.title LIKE ?'));
139:
140:            foreach ($keywordsList as $keyword) {
141:                $args[] = '%' . $keyword . '%';
142:            }
143:
144:            call_user_func_array(array($select, 'where'), $args);
145:        }
146:
147:        /** 给计算数目对象赋值,克隆对象 */
148:        $this->_countSql = clone $select;
149:
150:        /** 提交查询 */
151:        $select->order('table.contents.created', Typecho_Db::SORT_DESC)
152:        ->page($this->_currentPage, $this->parameter->pageSize);
153:
154:        $this->db->fetchAll($select, array($this, 'push'));
155:    }
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
91:    public function execute()
92:    {
93:        $this->parameter->setDefault('pageSize=20');
94:        $this->_currentPage = $this->request->get('page', 1);
95:
96:        /** 构建基础查询 */
97:        $select = $this->select();
98:
99:        /** 如果具有编辑以上权限,可以查看所有文章,反之只能查看自己的文章 */
100:        if (!$this->user->pass('editor', true)) {
101:            $select->where('table.contents.authorId = ?', $this->user->uid);
102:        } else {
103:            if ('on' == $this->request->__typecho_all_posts) {
104:                Typecho_Cookie::set('__typecho_all_posts', 'on');
105:            } else {
106:                if ('off' == $this->request->__typecho_all_posts) {
107:                    Typecho_Cookie::set('__typecho_all_posts', 'off');
108:                }
109:
110:                if ('on' != Typecho_Cookie::get('__typecho_all_posts')) {
111:                    $select->where('table.contents.authorId = ?', isset($this->request->uid) ?
112:                        $this->request->filter('int')->uid : $this->user->uid);
113:                }
114:            }
115:        }
116:
117:        /** 按状态查询 */
118:        if ('draft' == $this->request->status) {
119:            $select->where('table.contents.type = ?', 'post_draft');
120:        } else if ('waiting' == $this->request->status) {
121:            $select->where('(table.contents.type = ? OR table.contents.type = ?) AND table.contents.status = ?',
122:                'post', 'post_draft', 'waiting');
123:        } else {
124:            $select->where('table.contents.type = ? OR (table.contents.type = ? AND table.contents.parent = ?)',
125:                'post', 'post_draft', 0);
126:        }
127:
128:        /** 过滤分类 */
129:        if (NULL != ($category = $this->request->category)) {
130:            $select->join('table.relationships', 'table.contents.cid = table.relationships.cid')
131:            ->where('table.relationships.mid = ?', $category);
132:        }
133:
134:        /** 过滤标题 */
135:        if (NULL != ($keywords = $this->request->filter('search')->keywords)) {
136:            $args = array();
137:            $keywordsList = explode(' ', $keywords);
138:            $args[] = implode(' OR ', array_fill(0, count($keywordsList), 'table.contents.title LIKE ?'));
139:
140:            foreach ($keywordsList as $keyword) {
141:                $args[] = '%' . $keyword . '%';
142:            }
143:
144:            call_user_func_array(array($select, 'where'), $args);
145:        }
146:
147:        /** 给计算数目对象赋值,克隆对象 */
148:        $this->_countSql = clone $select;
149:
150:        /** 提交查询 */
151:        $select->order('table.contents.created', Typecho_Db::SORT_DESC)
152:        ->page($this->_currentPage, $this->parameter->pageSize);
153:
154:        $this->db->fetchAll($select, array($this, 'push'));
155:    }

./typecho/var/Widget/Contents/Attachment/Unattached.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
29:    public function execute()
30:    {
31:        /** 构建基础查询 */
32:        $select = $this->select()->where('table.contents.type = ? AND
33:        (table.contents.parent = 0 OR table.contents.parent IS NULL)', 'attachment');
34:        
35:        /** 加上对用户的判断 */
36:        $this->where('table.contents.authorId = ?', $this->user->uid);
37:
38:        /** 提交查询 */
39:        $select->order('table.contents.created', Typecho_Db::SORT_DESC);
40:
41:        $this->db->fetchAll($select, array($this, 'push'));
42:    }

./typecho/var/Widget/Contents/Attachment/Related.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
29:    public function execute()
30:    {
31:        $this->parameter->setDefault('parentId=0&limit=0');
32:
33:        //如果没有cid值
34:        if (!$this->parameter->parentId) {
35:            return;
36:        }
37:
38:        /** 构建基础查询 */
39:        $select = $this->select()->where('table.contents.type = ?', 'attachment');
40:
41:        //order字段在文件里代表所属文章
42:        $select->where('table.contents.parent = ?', $this->parameter->parentId);
43:
44:        /** 提交查询 */
45:        $select->order('table.contents.created', Typecho_Db::SORT_ASC);
46:
47:        if ($this->parameter->limit > 0) {
48:            $select->limit($this->parameter->limit);
49:        }
50:
51:        if ($this->parameter->offset > 0) {
52:            $select->offset($this->parameter->offset);
53:        }
54:
55:        $this->db->fetchAll($select, array($this, 'push'));
56:    }

./typecho/var/Widget/Contents/Attachment/Admin.php

等级 函数 说明
danger execute call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
74:    public function execute()
75:    {
76:        $this->parameter->setDefault('pageSize=20');
77:        $this->_currentPage = $this->request->get('page', 1);
78:
79:        /** 构建基础查询 */
80:        $select = $this->select()->where('table.contents.type = ?', 'attachment');
81:
82:        /** 如果具有编辑以上权限,可以查看所有文件,反之只能查看自己的文件 */
83:        if (!$this->user->pass('editor', true)) {
84:            $select->where('table.contents.authorId = ?', $this->user->uid);
85:        }
86:
87:        /** 过滤标题 */
88:        if (NULL != ($keywords = $this->request->filter('search')->keywords)) {
89:            $args = array();
90:            $keywordsList = explode(' ', $keywords);
91:            $args[] = implode(' OR ', array_fill(0, count($keywordsList), 'table.contents.title LIKE ?'));
92:
93:            foreach ($keywordsList as $keyword) {
94:                $args[] = '%' . $keyword . '%';
95:            }
96:
97:            call_user_func_array(array($select, 'where'), $args);
98:        }
99:
100:        /** 给计算数目对象赋值,克隆对象 */
101:        $this->_countSql = clone $select;
102:
103:        /** 提交查询 */
104:        $select->order('table.contents.created', Typecho_Db::SORT_DESC)
105:        ->page($this->_currentPage, $this->parameter->pageSize);
106:
107:        $this->db->fetchAll($select, array($this, 'push'));
108:    }
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
74:    public function execute()
75:    {
76:        $this->parameter->setDefault('pageSize=20');
77:        $this->_currentPage = $this->request->get('page', 1);
78:
79:        /** 构建基础查询 */
80:        $select = $this->select()->where('table.contents.type = ?', 'attachment');
81:
82:        /** 如果具有编辑以上权限,可以查看所有文件,反之只能查看自己的文件 */
83:        if (!$this->user->pass('editor', true)) {
84:            $select->where('table.contents.authorId = ?', $this->user->uid);
85:        }
86:
87:        /** 过滤标题 */
88:        if (NULL != ($keywords = $this->request->filter('search')->keywords)) {
89:            $args = array();
90:            $keywordsList = explode(' ', $keywords);
91:            $args[] = implode(' OR ', array_fill(0, count($keywordsList), 'table.contents.title LIKE ?'));
92:
93:            foreach ($keywordsList as $keyword) {
94:                $args[] = '%' . $keyword . '%';
95:            }
96:
97:            call_user_func_array(array($select, 'where'), $args);
98:        }
99:
100:        /** 给计算数目对象赋值,克隆对象 */
101:        $this->_countSql = clone $select;
102:
103:        /** 提交查询 */
104:        $select->order('table.contents.created', Typecho_Db::SORT_DESC)
105:        ->page($this->_currentPage, $this->parameter->pageSize);
106:
107:        $this->db->fetchAll($select, array($this, 'push'));
108:    }

./typecho/var/Widget/Contents/Related/Author.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
30:    public function execute()
31:    {
32:        $this->parameter->setDefault('limit=5');
33:
34:        if ($this->parameter->author) {
35:            $this->db->fetchAll($this->select()
36:            ->where('table.contents.authorId = ?', $this->parameter->author)
37:            ->where('table.contents.cid <> ?', $this->parameter->cid)
38:            ->where('table.contents.status = ?', 'publish')
39:            ->where('table.contents.password IS NULL')
40:            ->where('table.contents.created < ?', $this->options->gmtTime)
41:            ->where('table.contents.type = ?', $this->parameter->type)
42:            ->order('table.contents.created', Typecho_Db::SORT_DESC)
43:            ->limit($this->parameter->limit), array($this, 'push'));
44:        }
45:    }

./typecho/var/Widget/Contents/Related.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
44:    public function execute()
45:    {
46:        $this->parameter->setDefault('limit=5');
47:
48:        if ($this->parameter->tags) {
49:            $tagsGroup = implode(',', Typecho_Common::arrayFlatten($this->parameter->tags, 'mid'));
50:            $this->db->fetchAll($this->select()
51:            ->join('table.relationships', 'table.contents.cid = table.relationships.cid')
52:            ->where('table.relationships.mid IN (' . $tagsGroup . ')')
53:            ->where('table.contents.cid <> ?', $this->parameter->cid)
54:            ->where('table.contents.status = ?', 'publish')
55:            ->where('table.contents.password IS NULL')
56:            ->where('table.contents.created < ?', $this->options->gmtTime)
57:            ->where('table.contents.type = ?', $this->parameter->type)
58:            ->order('table.contents.created', Typecho_Db::SORT_DESC)
59:            ->limit($this->parameter->limit), array($this, 'push'));
60:        }
61:    }

./typecho/var/Widget/Archive.php

等级 函数 说明
danger import 动态调用方法,可能存在远程代码执行的隐患
代码
649:    private function import(Widget_Archive $widget)
650:    {
651:        $currentProperties = get_object_vars($this);
652:
653:        foreach ($currentProperties as $name => $value) {
654:            if (false !== strpos('|request|response|parameter|_feed|_feedType|_currentFeedUrl|', '|' . $name . '|')) {
655:                continue;
656:            }
657:
658:            if (isset($widget->{$name})) {
659:                $this->{$name} = $widget->{$name};
660:            } else {
661:                $method = ucfirst(trim($name, '_'));
662:                $setMethod = 'set' . $method;
663:                $getMethod = 'get' . $method;
664:
665:                if (method_exists($this, $setMethod)
666:                    && method_exists($widget, $getMethod)) {
667:                    $this->{$setMethod}($widget->{$getMethod}());
668:                }
669:            }
670:        }
671:    }
danger import 动态调用方法,可能存在远程代码执行的隐患
代码
649:    private function import(Widget_Archive $widget)
650:    {
651:        $currentProperties = get_object_vars($this);
652:
653:        foreach ($currentProperties as $name => $value) {
654:            if (false !== strpos('|request|response|parameter|_feed|_feedType|_currentFeedUrl|', '|' . $name . '|')) {
655:                continue;
656:            }
657:
658:            if (isset($widget->{$name})) {
659:                $this->{$name} = $widget->{$name};
660:            } else {
661:                $method = ucfirst(trim($name, '_'));
662:                $setMethod = 'set' . $method;
663:                $getMethod = 'get' . $method;
664:
665:                if (method_exists($this, $setMethod)
666:                    && method_exists($widget, $getMethod)) {
667:                    $this->{$setMethod}($widget->{$getMethod}());
668:                }
669:            }
670:        }
671:    }
danger query fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
1246:    public function query($select)
1247:    {
1248:        $this->pluginHandle()->trigger($queryPlugged)->query($this, $select);
1249:        if (!$queryPlugged) {
1250:            $this->db->fetchAll($select, array($this, 'push'));
1251:        }
1252:    }
danger execute 动态调用方法,可能存在远程代码执行的隐患
代码
1260:    public function execute()
1261:    {
1262:        /** 避免重复取数据 */
1263:        if ($this->have()) {
1264:            return;
1265:        }
1266:
1267:        $handles = array(
1268:            'index'                     =>  'indexHandle',
1269:            'index_page'                =>  'indexHandle',
1270:            'archive'                   =>  'archiveEmptyHandle',
1271:            'archive_page'              =>  'archiveEmptyHandle',
1272:            404                         =>  'error404Handle',
1273:            'single'                    =>  'singleHandle',
1274:            'page'                      =>  'singleHandle',
1275:            'post'                      =>  'singleHandle',
1276:            'attachment'                =>  'singleHandle',
1277:            'comment_page'              =>  'singleHandle',
1278:            'category'                  =>  'categoryHandle',
1279:            'category_page'             =>  'categoryHandle',
1280:            'tag'                       =>  'tagHandle',
1281:            'tag_page'                  =>  'tagHandle',
1282:            'author'                    =>  'authorHandle',
1283:            'author_page'               =>  'authorHandle',
1284:            'archive_year'              =>  'dateHandle',
1285:            'archive_year_page'         =>  'dateHandle',
1286:            'archive_month'             =>  'dateHandle',
1287:            'archive_month_page'        =>  'dateHandle',
1288:            'archive_day'               =>  'dateHandle',
1289:            'archive_day_page'          =>  'dateHandle',
1290:            'search'                    =>  'searchHandle',
1291:            'search_page'               =>  'searchHandle'
1292:        );
1293:
1294:        /** 处理搜索结果跳转 */
1295:        if (isset($this->request->s)) {
1296:            $filterKeywords = $this->request->filter('search')->s;
1297:
1298:            /** 跳转到搜索页 */
1299:            if (NULL != $filterKeywords) {
1300:                $this->response->redirect(Typecho_Router::url('search',
1301:                array('keywords' => urlencode($filterKeywords)), $this->options->index));
1302:            }
1303:        }
1304:
1305:        /** 自定义首页功能 */
1306:        $frontPage = $this->options->frontPage;
1307:        if (!$this->_invokeByFeed && ('index' == $this->parameter->type || 'index_page' == $this->parameter->type)) {
1308:            //显示某个页面
1309:            if (0 === strpos($frontPage, 'page:')) {
1310:                // 对某些变量做hack
1311:                $this->request->setParam('cid', intval(substr($frontPage, 5)));
1312:                $this->parameter->type = 'page';
1313:                $this->_makeSinglePageAsFrontPage = true;
1314:            } else if (0 === strpos($frontPage, 'file:')) {
1315:                // 显示某个文件
1316:                $this->setThemeFile(substr($frontPage, 5));
1317:                return;
1318:            }
1319:        }
1320:
1321:        if ('recent' != $frontPage && $this->options->frontArchive) {
1322:            $handles['archive'] = 'indexHandle';
1323:            $handles['archive_page'] = 'indexHandle';
1324:            $this->_archiveType = 'front';
1325:        }
1326:
1327:        /** 初始化分页变量 */
1328:        $this->_currentPage = isset($this->request->page) ? $this->request->page : 1;
1329:        $hasPushed = false;
1330:
1331:        /** select初始化 */
1332:        $select = $this->pluginHandle()->trigger($selectPlugged)->select($this);
1333:
1334:        /** 定时发布功能 */
1335:        if (!$selectPlugged) {
1336:            if ('post' == $this->parameter->type || 'page' == $this->parameter->type) {
1337:                if ($this->user->hasLogin()) {
1338:                    $select = $this->select()->where('table.contents.status = ? OR table.contents.status = ? OR
1339:                            (table.contents.status = ? AND table.contents.authorId = ?)',
1340:                            'publish', 'hidden', 'private', $this->user->uid);
1341:                } else {
1342:                    $select = $this->select()->where('table.contents.status = ? OR table.contents.status = ?',
1343:                            'publish', 'hidden');
1344:                }
1345:            } else {
1346:                if ($this->user->hasLogin()) {
1347:                    $select = $this->select()->where('table.contents.status = ? OR
1348:                            (table.contents.status = ? AND table.contents.authorId = ?)', 'publish', 'private', $this->user->uid);
1349:                } else {
1350:                    $select = $this->select()->where('table.contents.status = ?', 'publish');
1351:                }
1352:            }
1353:            $select->where('table.contents.created < ?', $this->options->gmtTime);
1354:        }
1355:
1356:        /** handle初始化 */
1357:        $this->pluginHandle()->handleInit($this, $select);
1358:
1359:        /** 初始化其它变量 */
1360:        $this->_feedUrl = $this->options->feedUrl;
1361:        $this->_feedRssUrl = $this->options->feedRssUrl;
1362:        $this->_feedAtomUrl = $this->options->feedAtomUrl;
1363:        $this->_keywords = $this->options->keywords;
1364:        $this->_description = $this->options->description; 
1365:
1366:        if (isset($handles[$this->parameter->type])) {
1367:            $handle = $handles[$this->parameter->type];
1368:            $this->{$handle}($select, $hasPushed);
1369:        } else {
1370:            $hasPushed = $this->pluginHandle()->handle($this->parameter->type, $this, $select);
1371:        }
1372:        
1373:        /** 初始化皮肤函数 */
1374:        $functionsFile = $this->_themeDir . 'functions.php';
1375:        if ((!$this->_invokeFromOutside || $this->parameter->type == 404) && file_exists($functionsFile)) {
1376:            require_once $functionsFile;
1377:            if (function_exists('themeInit')) {
1378:                themeInit($this);
1379:            }
1380:        }
1381:
1382:        /** 如果已经提前压入则直接返回 */
1383:        if ($hasPushed) {
1384:            return;
1385:        }
1386:
1387:        /** 仅输出文章 */
1388:        $this->_countSql = clone $select;
1389:
1390:        $select->order('table.contents.created', Typecho_Db::SORT_DESC)
1391:        ->page($this->_currentPage, $this->parameter->pageSize);
1392:        $this->query($select);
1393:    }
danger execute 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
1260:    public function execute()
1261:    {
1262:        /** 避免重复取数据 */
1263:        if ($this->have()) {
1264:            return;
1265:        }
1266:
1267:        $handles = array(
1268:            'index'                     =>  'indexHandle',
1269:            'index_page'                =>  'indexHandle',
1270:            'archive'                   =>  'archiveEmptyHandle',
1271:            'archive_page'              =>  'archiveEmptyHandle',
1272:            404                         =>  'error404Handle',
1273:            'single'                    =>  'singleHandle',
1274:            'page'                      =>  'singleHandle',
1275:            'post'                      =>  'singleHandle',
1276:            'attachment'                =>  'singleHandle',
1277:            'comment_page'              =>  'singleHandle',
1278:            'category'                  =>  'categoryHandle',
1279:            'category_page'             =>  'categoryHandle',
1280:            'tag'                       =>  'tagHandle',
1281:            'tag_page'                  =>  'tagHandle',
1282:            'author'                    =>  'authorHandle',
1283:            'author_page'               =>  'authorHandle',
1284:            'archive_year'              =>  'dateHandle',
1285:            'archive_year_page'         =>  'dateHandle',
1286:            'archive_month'             =>  'dateHandle',
1287:            'archive_month_page'        =>  'dateHandle',
1288:            'archive_day'               =>  'dateHandle',
1289:            'archive_day_page'          =>  'dateHandle',
1290:            'search'                    =>  'searchHandle',
1291:            'search_page'               =>  'searchHandle'
1292:        );
1293:
1294:        /** 处理搜索结果跳转 */
1295:        if (isset($this->request->s)) {
1296:            $filterKeywords = $this->request->filter('search')->s;
1297:
1298:            /** 跳转到搜索页 */
1299:            if (NULL != $filterKeywords) {
1300:                $this->response->redirect(Typecho_Router::url('search',
1301:                array('keywords' => urlencode($filterKeywords)), $this->options->index));
1302:            }
1303:        }
1304:
1305:        /** 自定义首页功能 */
1306:        $frontPage = $this->options->frontPage;
1307:        if (!$this->_invokeByFeed && ('index' == $this->parameter->type || 'index_page' == $this->parameter->type)) {
1308:            //显示某个页面
1309:            if (0 === strpos($frontPage, 'page:')) {
1310:                // 对某些变量做hack
1311:                $this->request->setParam('cid', intval(substr($frontPage, 5)));
1312:                $this->parameter->type = 'page';
1313:                $this->_makeSinglePageAsFrontPage = true;
1314:            } else if (0 === strpos($frontPage, 'file:')) {
1315:                // 显示某个文件
1316:                $this->setThemeFile(substr($frontPage, 5));
1317:                return;
1318:            }
1319:        }
1320:
1321:        if ('recent' != $frontPage && $this->options->frontArchive) {
1322:            $handles['archive'] = 'indexHandle';
1323:            $handles['archive_page'] = 'indexHandle';
1324:            $this->_archiveType = 'front';
1325:        }
1326:
1327:        /** 初始化分页变量 */
1328:        $this->_currentPage = isset($this->request->page) ? $this->request->page : 1;
1329:        $hasPushed = false;
1330:
1331:        /** select初始化 */
1332:        $select = $this->pluginHandle()->trigger($selectPlugged)->select($this);
1333:
1334:        /** 定时发布功能 */
1335:        if (!$selectPlugged) {
1336:            if ('post' == $this->parameter->type || 'page' == $this->parameter->type) {
1337:                if ($this->user->hasLogin()) {
1338:                    $select = $this->select()->where('table.contents.status = ? OR table.contents.status = ? OR
1339:                            (table.contents.status = ? AND table.contents.authorId = ?)',
1340:                            'publish', 'hidden', 'private', $this->user->uid);
1341:                } else {
1342:                    $select = $this->select()->where('table.contents.status = ? OR table.contents.status = ?',
1343:                            'publish', 'hidden');
1344:                }
1345:            } else {
1346:                if ($this->user->hasLogin()) {
1347:                    $select = $this->select()->where('table.contents.status = ? OR
1348:                            (table.contents.status = ? AND table.contents.authorId = ?)', 'publish', 'private', $this->user->uid);
1349:                } else {
1350:                    $select = $this->select()->where('table.contents.status = ?', 'publish');
1351:                }
1352:            }
1353:            $select->where('table.contents.created < ?', $this->options->gmtTime);
1354:        }
1355:
1356:        /** handle初始化 */
1357:        $this->pluginHandle()->handleInit($this, $select);
1358:
1359:        /** 初始化其它变量 */
1360:        $this->_feedUrl = $this->options->feedUrl;
1361:        $this->_feedRssUrl = $this->options->feedRssUrl;
1362:        $this->_feedAtomUrl = $this->options->feedAtomUrl;
1363:        $this->_keywords = $this->options->keywords;
1364:        $this->_description = $this->options->description; 
1365:
1366:        if (isset($handles[$this->parameter->type])) {
1367:            $handle = $handles[$this->parameter->type];
1368:            $this->{$handle}($select, $hasPushed);
1369:        } else {
1370:            $hasPushed = $this->pluginHandle()->handle($this->parameter->type, $this, $select);
1371:        }
1372:        
1373:        /** 初始化皮肤函数 */
1374:        $functionsFile = $this->_themeDir . 'functions.php';
1375:        if ((!$this->_invokeFromOutside || $this->parameter->type == 404) && file_exists($functionsFile)) {
1376:            require_once $functionsFile;
1377:            if (function_exists('themeInit')) {
1378:                themeInit($this);
1379:            }
1380:        }
1381:
1382:        /** 如果已经提前压入则直接返回 */
1383:        if ($hasPushed) {
1384:            return;
1385:        }
1386:
1387:        /** 仅输出文章 */
1388:        $this->_countSql = clone $select;
1389:
1390:        $select->order('table.contents.created', Typecho_Db::SORT_DESC)
1391:        ->page($this->_currentPage, $this->parameter->pageSize);
1392:        $this->query($select);
1393:    }
danger pageLink 动态调用方法,可能存在远程代码执行的隐患
代码
1464:    public function pageLink($word = '&laquo; Previous Entries', $page = 'prev')
1465:    {
1466:        if ($this->have()) {
1467:            if (empty($this->_pageNav)) {
1468:                $query = Typecho_Router::url($this->parameter->type .
1469:                (false === strpos($this->parameter->type, '_page') ? '_page' : NULL),
1470:                $this->_pageRow, $this->options->index);
1471:
1472:                /** 使用盒状分页 */
1473:                $this->_pageNav = new Typecho_Widget_Helper_PageNavigator_Classic($this->getTotal(),
1474:                $this->_currentPage, $this->parameter->pageSize, $query);
1475:            }
1476:
1477:            $this->_pageNav->{$page}($word);
1478:        }
1479:    }
danger need 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
1935:    public function need($fileName)
1936:    {
1937:        require $this->_themeDir . $fileName;
1938:    }
danger render 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
1946:    public function render()
1947:    {
1948:        /** 处理静态链接跳转 */
1949:        $this->checkPermalink();
1950:        
1951:        /** 添加Pingback */
1952:        $this->response->setHeader('X-Pingback', $this->options->xmlRpcUrl);
1953:        $validated = false;
1954:
1955:        //~ 自定义模板
1956:        if (!empty($this->_themeFile)) {
1957:            if (file_exists($this->_themeDir . $this->_themeFile)) {
1958:                $validated = true;
1959:            }
1960:        }
1961:        
1962:        if (!$validated && !empty($this->_archiveType)) {
1963:
1964:            //~ 首先找具体路径, 比如 category/default.php
1965:            if (!$validated && !empty($this->_archiveSlug)) {
1966:                $themeFile = $this->_archiveType . '/' . $this->_archiveSlug . '.php';
1967:                if (file_exists($this->_themeDir . $themeFile)) {
1968:                    $this->_themeFile = $themeFile;
1969:                    $validated = true;
1970:                }
1971:            }
1972:
1973:            //~ 然后找归档类型路径, 比如 category.php
1974:            if (!$validated) {
1975:                $themeFile = $this->_archiveType . '.php';
1976:                if (file_exists($this->_themeDir . $themeFile)) {
1977:                    $this->_themeFile = $themeFile;
1978:                    $validated = true;
1979:                }
1980:            }
1981:
1982:            //针对attachment的hook
1983:            if (!$validated && 'attachment' == $this->_archiveType) {
1984:                if (file_exists($this->_themeDir . 'page.php')) {
1985:                    $this->_themeFile = 'page.php';
1986:                    $validated = true;
1987:                } else if (file_exists($this->_themeDir . 'post.php')) {
1988:                    $this->_themeFile = 'post.php';
1989:                    $validated = true;
1990:                }
1991:            }
1992:
1993:            //~ 最后找归档路径, 比如 archive.php 或者 single.php
1994:            if (!$validated && 'index' != $this->_archiveType && 'front' != $this->_archiveType) {
1995:                $themeFile = $this->_archiveSingle ? 'single.php' : 'archive.php';
1996:                if (file_exists($this->_themeDir . $themeFile)) {
1997:                    $this->_themeFile = $themeFile;
1998:                    $validated = true;
1999:                }
2000:            }
2001:
2002:            if (!$validated) {
2003:                $themeFile = 'index.php';
2004:                if (file_exists($this->_themeDir . $themeFile)) {
2005:                    $this->_themeFile = $themeFile;
2006:                    $validated = true;
2007:                }
2008:            }
2009:        }
2010:
2011:        /** 文件不存在 */
2012:        if (!$validated) {
2013:            Typecho_Common::error(500);
2014:        }
2015:
2016:        /** 挂接插件 */
2017:        $this->pluginHandle()->beforeRender($this);
2018:
2019:        /** 输出模板 */
2020:        require_once $this->_themeDir . $this->_themeFile;
2021:
2022:        /** 挂接插件 */
2023:        $this->pluginHandle()->afterRender($this);
2024:    }

./typecho/var/Widget/Plugins/Config.php

等级 函数 说明
danger config 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
83:    public function config()
84:    {
85:        /** 获取插件名称 */
86:        $pluginName = $this->request->filter('slug')->config;
87:
88:        /** 获取已启用插件 */
89:        $plugins = Typecho_Plugin::export();
90:        $activatedPlugins = $plugins['activated'];
91:
92:        /** 判断实例化是否成功 */
93:        if (!$this->info['config'] || !isset($activatedPlugins[$pluginName])) {
94:            throw new Typecho_Widget_Exception(_t('无法配置插件'), 500);
95:        }
96:
97:        /** 载入插件 */
98:        require_once $this->_pluginFileName;
99:        $form = new Typecho_Widget_Helper_Form($this->security->getIndex('/action/plugins-edit?config=' . $pluginName),
100:            Typecho_Widget_Helper_Form::POST_METHOD);
101:        call_user_func(array($this->_className, 'config'), $form);
102:
103:        $options = $this->options->plugin($pluginName);
104:
105:        if (!empty($options)) {
106:            foreach ($options as $key => $val) {
107:                $form->getInput($key)->value($val);
108:            }
109:        }
110:
111:        $submit = new Typecho_Widget_Helper_Form_Element_Submit(NULL, NULL, _t('保存设置'));
112:        $submit->input->setAttribute('class', 'btn primary');
113:        $form->addItem($submit);
114:        return $form;
115:    }
danger config call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
83:    public function config()
84:    {
85:        /** 获取插件名称 */
86:        $pluginName = $this->request->filter('slug')->config;
87:
88:        /** 获取已启用插件 */
89:        $plugins = Typecho_Plugin::export();
90:        $activatedPlugins = $plugins['activated'];
91:
92:        /** 判断实例化是否成功 */
93:        if (!$this->info['config'] || !isset($activatedPlugins[$pluginName])) {
94:            throw new Typecho_Widget_Exception(_t('无法配置插件'), 500);
95:        }
96:
97:        /** 载入插件 */
98:        require_once $this->_pluginFileName;
99:        $form = new Typecho_Widget_Helper_Form($this->security->getIndex('/action/plugins-edit?config=' . $pluginName),
100:            Typecho_Widget_Helper_Form::POST_METHOD);
101:        call_user_func(array($this->_className, 'config'), $form);
102:
103:        $options = $this->options->plugin($pluginName);
104:
105:        if (!empty($options)) {
106:            foreach ($options as $key => $val) {
107:                $form->getInput($key)->value($val);
108:            }
109:        }
110:
111:        $submit = new Typecho_Widget_Helper_Form_Element_Submit(NULL, NULL, _t('保存设置'));
112:        $submit->input->setAttribute('class', 'btn primary');
113:        $form->addItem($submit);
114:        return $form;
115:    }

./typecho/var/Widget/Plugins/Edit.php

等级 函数 说明
danger activate 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
78:    public function activate($pluginName)
79:    {
80:        /** 获取插件入口 */
81:        list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
82:        $info = Typecho_Plugin::parseInfo($pluginFileName);
83:
84:        /** 检测依赖信息 */
85:        list ($version, $build) = explode('/', Typecho_Common::VERSION);
86:        if (Typecho_Plugin::checkDependence($build, $info['dependence'])) {
87:
88:            /** 获取已启用插件 */
89:            $plugins = Typecho_Plugin::export();
90:            $activatedPlugins = $plugins['activated'];
91:
92:            /** 载入插件 */
93:            require_once $pluginFileName;
94:
95:            /** 判断实例化是否成功 */
96:            if (isset($activatedPlugins[$pluginName]) || !class_exists($className)
97:            || !method_exists($className, 'activate')) {
98:                throw new Typecho_Widget_Exception(_t('无法启用插件'), 500);
99:            }
100:
101:            try {
102:                $result = call_user_func(array($className, 'activate'));
103:                Typecho_Plugin::activate($pluginName);
104:                $this->update(array('value' => serialize(Typecho_Plugin::export())),
105:                $this->db->sql()->where('name = ?', 'plugins'));
106:            } catch (Typecho_Plugin_Exception $e) {
107:                /** 截获异常 */
108:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
109:                $this->response->goBack();
110:            }
111:
112:            $form = new Typecho_Widget_Helper_Form();
113:            call_user_func(array($className, 'config'), $form);
114:
115:            $personalForm = new Typecho_Widget_Helper_Form();
116:            call_user_func(array($className, 'personalConfig'), $personalForm);
117:
118:            $options = $form->getValues();
119:            $personalOptions = $personalForm->getValues();
120:
121:            if ($options && !$this->configHandle($pluginName, $options, true)) {
122:                self::configPlugin($pluginName, $options);
123:            }
124:
125:            if ($personalOptions && !$this->personalConfigHandle($className, $personalOptions)) {
126:                self::configPlugin($pluginName, $personalOptions, true);
127:            }
128:
129:        } else {
130:
131:            $result = _t('<a href="%s">%s</a> 无法在此版本的typecho下正常工作', $info['link'], $info['title']);
132:
133:        }
134:
135:        /** 设置高亮 */
136:        $this->widget('Widget_Notice')->highlight('plugin-' . $pluginName);
137:
138:        if (isset($result) && is_string($result)) {
139:            $this->widget('Widget_Notice')->set($result, 'notice');
140:        } else {
141:            $this->widget('Widget_Notice')->set(_t('插件已经被启用'), 'success');
142:        }
143:        $this->response->goBack();
144:    }
danger activate call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
78:    public function activate($pluginName)
79:    {
80:        /** 获取插件入口 */
81:        list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
82:        $info = Typecho_Plugin::parseInfo($pluginFileName);
83:
84:        /** 检测依赖信息 */
85:        list ($version, $build) = explode('/', Typecho_Common::VERSION);
86:        if (Typecho_Plugin::checkDependence($build, $info['dependence'])) {
87:
88:            /** 获取已启用插件 */
89:            $plugins = Typecho_Plugin::export();
90:            $activatedPlugins = $plugins['activated'];
91:
92:            /** 载入插件 */
93:            require_once $pluginFileName;
94:
95:            /** 判断实例化是否成功 */
96:            if (isset($activatedPlugins[$pluginName]) || !class_exists($className)
97:            || !method_exists($className, 'activate')) {
98:                throw new Typecho_Widget_Exception(_t('无法启用插件'), 500);
99:            }
100:
101:            try {
102:                $result = call_user_func(array($className, 'activate'));
103:                Typecho_Plugin::activate($pluginName);
104:                $this->update(array('value' => serialize(Typecho_Plugin::export())),
105:                $this->db->sql()->where('name = ?', 'plugins'));
106:            } catch (Typecho_Plugin_Exception $e) {
107:                /** 截获异常 */
108:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
109:                $this->response->goBack();
110:            }
111:
112:            $form = new Typecho_Widget_Helper_Form();
113:            call_user_func(array($className, 'config'), $form);
114:
115:            $personalForm = new Typecho_Widget_Helper_Form();
116:            call_user_func(array($className, 'personalConfig'), $personalForm);
117:
118:            $options = $form->getValues();
119:            $personalOptions = $personalForm->getValues();
120:
121:            if ($options && !$this->configHandle($pluginName, $options, true)) {
122:                self::configPlugin($pluginName, $options);
123:            }
124:
125:            if ($personalOptions && !$this->personalConfigHandle($className, $personalOptions)) {
126:                self::configPlugin($pluginName, $personalOptions, true);
127:            }
128:
129:        } else {
130:
131:            $result = _t('<a href="%s">%s</a> 无法在此版本的typecho下正常工作', $info['link'], $info['title']);
132:
133:        }
134:
135:        /** 设置高亮 */
136:        $this->widget('Widget_Notice')->highlight('plugin-' . $pluginName);
137:
138:        if (isset($result) && is_string($result)) {
139:            $this->widget('Widget_Notice')->set($result, 'notice');
140:        } else {
141:            $this->widget('Widget_Notice')->set(_t('插件已经被启用'), 'success');
142:        }
143:        $this->response->goBack();
144:    }
danger activate call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
78:    public function activate($pluginName)
79:    {
80:        /** 获取插件入口 */
81:        list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
82:        $info = Typecho_Plugin::parseInfo($pluginFileName);
83:
84:        /** 检测依赖信息 */
85:        list ($version, $build) = explode('/', Typecho_Common::VERSION);
86:        if (Typecho_Plugin::checkDependence($build, $info['dependence'])) {
87:
88:            /** 获取已启用插件 */
89:            $plugins = Typecho_Plugin::export();
90:            $activatedPlugins = $plugins['activated'];
91:
92:            /** 载入插件 */
93:            require_once $pluginFileName;
94:
95:            /** 判断实例化是否成功 */
96:            if (isset($activatedPlugins[$pluginName]) || !class_exists($className)
97:            || !method_exists($className, 'activate')) {
98:                throw new Typecho_Widget_Exception(_t('无法启用插件'), 500);
99:            }
100:
101:            try {
102:                $result = call_user_func(array($className, 'activate'));
103:                Typecho_Plugin::activate($pluginName);
104:                $this->update(array('value' => serialize(Typecho_Plugin::export())),
105:                $this->db->sql()->where('name = ?', 'plugins'));
106:            } catch (Typecho_Plugin_Exception $e) {
107:                /** 截获异常 */
108:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
109:                $this->response->goBack();
110:            }
111:
112:            $form = new Typecho_Widget_Helper_Form();
113:            call_user_func(array($className, 'config'), $form);
114:
115:            $personalForm = new Typecho_Widget_Helper_Form();
116:            call_user_func(array($className, 'personalConfig'), $personalForm);
117:
118:            $options = $form->getValues();
119:            $personalOptions = $personalForm->getValues();
120:
121:            if ($options && !$this->configHandle($pluginName, $options, true)) {
122:                self::configPlugin($pluginName, $options);
123:            }
124:
125:            if ($personalOptions && !$this->personalConfigHandle($className, $personalOptions)) {
126:                self::configPlugin($pluginName, $personalOptions, true);
127:            }
128:
129:        } else {
130:
131:            $result = _t('<a href="%s">%s</a> 无法在此版本的typecho下正常工作', $info['link'], $info['title']);
132:
133:        }
134:
135:        /** 设置高亮 */
136:        $this->widget('Widget_Notice')->highlight('plugin-' . $pluginName);
137:
138:        if (isset($result) && is_string($result)) {
139:            $this->widget('Widget_Notice')->set($result, 'notice');
140:        } else {
141:            $this->widget('Widget_Notice')->set(_t('插件已经被启用'), 'success');
142:        }
143:        $this->response->goBack();
144:    }
danger activate call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
78:    public function activate($pluginName)
79:    {
80:        /** 获取插件入口 */
81:        list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
82:        $info = Typecho_Plugin::parseInfo($pluginFileName);
83:
84:        /** 检测依赖信息 */
85:        list ($version, $build) = explode('/', Typecho_Common::VERSION);
86:        if (Typecho_Plugin::checkDependence($build, $info['dependence'])) {
87:
88:            /** 获取已启用插件 */
89:            $plugins = Typecho_Plugin::export();
90:            $activatedPlugins = $plugins['activated'];
91:
92:            /** 载入插件 */
93:            require_once $pluginFileName;
94:
95:            /** 判断实例化是否成功 */
96:            if (isset($activatedPlugins[$pluginName]) || !class_exists($className)
97:            || !method_exists($className, 'activate')) {
98:                throw new Typecho_Widget_Exception(_t('无法启用插件'), 500);
99:            }
100:
101:            try {
102:                $result = call_user_func(array($className, 'activate'));
103:                Typecho_Plugin::activate($pluginName);
104:                $this->update(array('value' => serialize(Typecho_Plugin::export())),
105:                $this->db->sql()->where('name = ?', 'plugins'));
106:            } catch (Typecho_Plugin_Exception $e) {
107:                /** 截获异常 */
108:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
109:                $this->response->goBack();
110:            }
111:
112:            $form = new Typecho_Widget_Helper_Form();
113:            call_user_func(array($className, 'config'), $form);
114:
115:            $personalForm = new Typecho_Widget_Helper_Form();
116:            call_user_func(array($className, 'personalConfig'), $personalForm);
117:
118:            $options = $form->getValues();
119:            $personalOptions = $personalForm->getValues();
120:
121:            if ($options && !$this->configHandle($pluginName, $options, true)) {
122:                self::configPlugin($pluginName, $options);
123:            }
124:
125:            if ($personalOptions && !$this->personalConfigHandle($className, $personalOptions)) {
126:                self::configPlugin($pluginName, $personalOptions, true);
127:            }
128:
129:        } else {
130:
131:            $result = _t('<a href="%s">%s</a> 无法在此版本的typecho下正常工作', $info['link'], $info['title']);
132:
133:        }
134:
135:        /** 设置高亮 */
136:        $this->widget('Widget_Notice')->highlight('plugin-' . $pluginName);
137:
138:        if (isset($result) && is_string($result)) {
139:            $this->widget('Widget_Notice')->set($result, 'notice');
140:        } else {
141:            $this->widget('Widget_Notice')->set(_t('插件已经被启用'), 'success');
142:        }
143:        $this->response->goBack();
144:    }
danger deactivate 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
154:    public function deactivate($pluginName)
155:    {
156:        /** 获取已启用插件 */
157:        $plugins = Typecho_Plugin::export();
158:        $activatedPlugins = $plugins['activated'];
159:        $pluginFileExist = true;
160:
161:        try {
162:            /** 获取插件入口 */
163:            list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
164:        } catch (Typecho_Plugin_Exception $e) {
165:            $pluginFileExist = false;
166:
167:            if (!isset($activatedPlugins[$pluginName])) {
168:                throw $e;
169:            }
170:        }
171:
172:        /** 判断实例化是否成功 */
173:        if (!isset($activatedPlugins[$pluginName])) {
174:            throw new Typecho_Widget_Exception(_t('无法禁用插件'), 500);
175:        }
176:
177:        if ($pluginFileExist) {
178:
179:            /** 载入插件 */
180:            require_once $pluginFileName;
181:
182:            /** 判断实例化是否成功 */
183:            if (!isset($activatedPlugins[$pluginName]) || !class_exists($className)
184:            || !method_exists($className, 'deactivate')) {
185:                throw new Typecho_Widget_Exception(_t('无法禁用插件'), 500);
186:            }
187:
188:            try {
189:                $result = call_user_func(array($className, 'deactivate'));
190:            } catch (Typecho_Plugin_Exception $e) {
191:                /** 截获异常 */
192:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
193:                $this->response->goBack();
194:            }
195:
196:            /** 设置高亮 */
197:            $this->widget('Widget_Notice')->highlight('plugin-' . $pluginName);
198:        }
199:
200:        Typecho_Plugin::deactivate($pluginName);
201:        $this->update(array('value' => serialize(Typecho_Plugin::export())),
202:        $this->db->sql()->where('name = ?', 'plugins'));
203:
204:        $this->delete($this->db->sql()->where('name = ?', 'plugin:' . $pluginName));
205:        $this->delete($this->db->sql()->where('name = ?', '_plugin:' . $pluginName));
206:
207:        if (isset($result) && is_string($result)) {
208:            $this->widget('Widget_Notice')->set($result, 'notice');
209:        } else {
210:            $this->widget('Widget_Notice')->set(_t('插件已经被禁用'), 'success');
211:        }
212:        $this->response->goBack();
213:    }
danger deactivate call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
154:    public function deactivate($pluginName)
155:    {
156:        /** 获取已启用插件 */
157:        $plugins = Typecho_Plugin::export();
158:        $activatedPlugins = $plugins['activated'];
159:        $pluginFileExist = true;
160:
161:        try {
162:            /** 获取插件入口 */
163:            list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
164:        } catch (Typecho_Plugin_Exception $e) {
165:            $pluginFileExist = false;
166:
167:            if (!isset($activatedPlugins[$pluginName])) {
168:                throw $e;
169:            }
170:        }
171:
172:        /** 判断实例化是否成功 */
173:        if (!isset($activatedPlugins[$pluginName])) {
174:            throw new Typecho_Widget_Exception(_t('无法禁用插件'), 500);
175:        }
176:
177:        if ($pluginFileExist) {
178:
179:            /** 载入插件 */
180:            require_once $pluginFileName;
181:
182:            /** 判断实例化是否成功 */
183:            if (!isset($activatedPlugins[$pluginName]) || !class_exists($className)
184:            || !method_exists($className, 'deactivate')) {
185:                throw new Typecho_Widget_Exception(_t('无法禁用插件'), 500);
186:            }
187:
188:            try {
189:                $result = call_user_func(array($className, 'deactivate'));
190:            } catch (Typecho_Plugin_Exception $e) {
191:                /** 截获异常 */
192:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
193:                $this->response->goBack();
194:            }
195:
196:            /** 设置高亮 */
197:            $this->widget('Widget_Notice')->highlight('plugin-' . $pluginName);
198:        }
199:
200:        Typecho_Plugin::deactivate($pluginName);
201:        $this->update(array('value' => serialize(Typecho_Plugin::export())),
202:        $this->db->sql()->where('name = ?', 'plugins'));
203:
204:        $this->delete($this->db->sql()->where('name = ?', 'plugin:' . $pluginName));
205:        $this->delete($this->db->sql()->where('name = ?', '_plugin:' . $pluginName));
206:
207:        if (isset($result) && is_string($result)) {
208:            $this->widget('Widget_Notice')->set($result, 'notice');
209:        } else {
210:            $this->widget('Widget_Notice')->set(_t('插件已经被禁用'), 'success');
211:        }
212:        $this->response->goBack();
213:    }
danger configHandle call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
258:    public function configHandle($pluginName, array $settings, $isInit)
259:    {
260:        /** 获取插件入口 */
261:        list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
262:
263:        if (!$isInit && method_exists($className, 'configCheck')) {
264:            $result = call_user_func(array($className, 'configCheck'), $settings);
265:
266:            if (!empty($result) && is_string($result)) {
267:                $this->widget('Widget_Notice')->set($result, 'notice');
268:                $this->_configNoticed = true;
269:            }
270:        }
271:
272:        if (method_exists($className, 'configHandle')) {
273:            call_user_func(array($className, 'configHandle'), $settings, $isInit);
274:            return true;
275:        }
276:
277:        return false;
278:    }
danger configHandle call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
258:    public function configHandle($pluginName, array $settings, $isInit)
259:    {
260:        /** 获取插件入口 */
261:        list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, $this->options->pluginDir($pluginName));
262:
263:        if (!$isInit && method_exists($className, 'configCheck')) {
264:            $result = call_user_func(array($className, 'configCheck'), $settings);
265:
266:            if (!empty($result) && is_string($result)) {
267:                $this->widget('Widget_Notice')->set($result, 'notice');
268:                $this->_configNoticed = true;
269:            }
270:        }
271:
272:        if (method_exists($className, 'configHandle')) {
273:            call_user_func(array($className, 'configHandle'), $settings, $isInit);
274:            return true;
275:        }
276:
277:        return false;
278:    }
danger personalConfigHandle call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
288:    public function personalConfigHandle($className, array $settings)
289:    {
290:        if (method_exists($className, 'personalConfigHandle')) {
291:            call_user_func(array($className, 'personalConfigHandle'), $settings, true);
292:            return true;
293:        }
294:
295:        return false;
296:    }

./typecho/var/Widget/XmlRpc.php

等级 函数 说明
danger mwNewPost fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
1369:    public function mwNewPost($blogId, $userName, $password, $content, $publish)
1370:    {
1371:        /** 检查权限*/
1372:        if (!$this->checkAccess($userName, $password)) {
1373:            return $this->error;
1374:        }
1375:
1376:        /** 取得content内容 */
1377:        $input = array();
1378:        $type = isset($content['post_type']) && 'page' == $content['post_type'] ? 'page' : 'post';
1379:        
1380:        $input['title'] = trim($content['title']) == NULL ? _t('未命名文档') : $content['title'];
1381:
1382:        if (isset($content['slug'])) {
1383:            $input['slug'] = $content['slug'];
1384:        } else if (isset($content['wp_slug'])) {
1385:            //fix issue 338, wlw只发送这个
1386:            $input['slug'] = $content['wp_slug'];
1387:        }
1388:
1389:        $input['text'] = !empty($content['mt_text_more']) ? $content['description'] 
1390:            . "\n<!--more-->\n" . $content['mt_text_more'] : $content['description'];
1391:        $input['text'] = $this->pluginHandle()->textFilter($input['text'], $this); 
1392:        
1393:        $input['password'] = isset($content["wp_password"]) ? $content["wp_password"] : NULL;
1394:        $input['order'] = isset($content["wp_page_order"]) ? $content["wp_page_order"] : NULL;
1395:
1396:        $input['tags'] = isset($content['mt_keywords']) ? $content['mt_keywords'] : NULL;
1397:        $input['category'] = array();
1398:
1399:        if (isset($content['postId'])) {
1400:            $input['cid'] = $content['postId'];
1401:        }
1402:        
1403:        if ('page' == $type && isset($content['wp_page_template'])) {
1404:            $input['template'] = $content['wp_page_template'];
1405:        }
1406:
1407:        if (isset($content['dateCreated'])) {
1408:            /** 解决客户端与服务器端时间偏移 */
1409:            $input['created'] = $content['dateCreated']->getTimestamp() - $this->options->timezone + $this->options->serverTimezone;
1410:        }
1411:
1412:        if (!empty($content['categories']) && is_array($content['categories'])) {
1413:            foreach ($content['categories'] as $category) {
1414:                if (!$this->db->fetchRow($this->db->select('mid')
1415:                ->from('table.metas')->where('type = ? AND name = ?', 'category', $category))) {
1416:                    $result = $this->wpNewCategory($blogId, $userName, $password, array('name' => $category));
1417:                    if (true !== $result) {
1418:                        return $result;
1419:                    }
1420:                }
1421:
1422:                $input['category'][] = $this->db->fetchObject($this->db->select('mid')
1423:                ->from('table.metas')->where('type = ? AND name = ?', 'category', $category)
1424:                ->limit(1))->mid;
1425:            }
1426:        }
1427:
1428:        $input['allowComment'] = (isset($content['mt_allow_comments']) && (1 == $content['mt_allow_comments']
1429:        || 'open' == $content['mt_allow_comments'])) ? 1 : ((isset($content['mt_allow_comments']) && (0 == $content['mt_allow_comments']
1430:        || 'closed' == $content['mt_allow_comments'])) ? 0 : $this->options->defaultAllowComment);
1431:
1432:        $input['allowPing'] = (isset($content['mt_allow_pings']) && (1 == $content['mt_allow_pings']
1433:        || 'open' == $content['mt_allow_pings'])) ? 1 : ((isset($content['mt_allow_pings']) && (0 == $content['mt_allow_pings']
1434:        || 'closed' == $content['mt_allow_pings'])) ? 0 : $this->options->defaultAllowPing);
1435:
1436:        $input['allowFeed'] = $this->options->defaultAllowFeed;
1437:        $input['do'] = $publish ? 'publish' : 'save';
1438:        $input['markdown'] = $this->options->xmlrpcMarkdown;
1439:        
1440:        /** 调整状态 */
1441:        if (isset($content["{$type}_status"])) {
1442:            $status = $this->wordpressToTypechoStatus($content["{$type}_status"], $type);
1443:            
1444:            if ('publish' == $status || 'waiting' == $status || 'private' == $status) {
1445:                $input['do'] = 'publish';
1446:                
1447:                if ('private' == $status) {
1448:                    $input['private'] = 1;
1449:                }
1450:            } else {
1451:                $input['do'] = 'save';
1452:            }
1453:        }
1454:
1455:        /** 对未归档附件进行归档 */
1456:        $unattached = $this->db->fetchAll($this->select()->where('table.contents.type = ? AND
1457:        (table.contents.parent = 0 OR table.contents.parent IS NULL)', 'attachment'), array($this, 'filter'));
1458:
1459:        if (!empty($unattached)) {
1460:            foreach ($unattached as $attach) {
1461:                if (false !== strpos($input['text'], $attach['attachment']->url)) {
1462:                    if (!isset($input['attachment'])) {
1463:                        $input['attachment'] = array();
1464:                    }
1465:
1466:                    $input['attachment'][] = $attach['cid'];
1467:                }
1468:            }
1469:        }
1470:
1471:        /** 调用已有组件 */
1472:        try {
1473:            /** 插入 */
1474:            if ('page' == $type) {
1475:                $this->singletonWidget('Widget_Contents_Page_Edit', NULL, $input, false)->action();
1476:            } else {
1477:                $this->singletonWidget('Widget_Contents_Post_Edit', NULL, $input, false)->action();
1478:            }
1479:        
1480:            return $this->singletonWidget('Widget_Notice')->getHighlightId();
1481:        } catch (Typecho_Widget_Exception $e) {
1482:            return new IXR_Error($e->getCode(), $e->getMessage());
1483:        }
1484:    }

./typecho/var/Widget/Do.php

等级 函数 说明
warning execute PHP反射类被创建,可能导致远程代码执行漏洞
代码
57:    public function execute()
58:    {
59:        /** 验证路由地址 **/
60:        $action = $this->request->action;
61:
62:        //兼容老版本
63:        if (empty($action)) {
64:            $widget = trim($this->request->widget, '/');
65:            $objectName = 'Widget_' . str_replace('/', '_', $widget);
66:
67:            if (Typecho_Common::isAvailableClass($objectName)) {
68:                $widgetName = $objectName;
69:            }
70:        } else {
71:            /** 判断是否为plugin */
72:            $actionTable = array_merge($this->_map, unserialize($this->widget('Widget_Options')->actionTable));
73:
74:            if (isset($actionTable[$action])) {
75:                $widgetName = $actionTable[$action];
76:            }
77:        }
78:
79:        if (isset($widgetName) && class_exists($widgetName)) {
80:            $reflectionWidget =  new ReflectionClass($widgetName);
81:            if ($reflectionWidget->implementsInterface('Widget_Interface_Do')) {
82:                $this->widget($widgetName)->action();
83:                return;
84:            }
85:        }
86:
87:        throw new Typecho_Widget_Exception(_t('请求的地址不存在'), 404);
88:    }

./typecho/var/Widget/Upgrade.php

等级 函数 说明
danger upgrade array_filter第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
69:    public function upgrade()
70:    {
71:        list($prefix, $this->_currentVersion) = explode('/', $this->options->generator);
72:        $packages = get_class_methods('Upgrade');
73:        $packages = array_filter($packages, array($this, 'filterPackage'));
74:        usort($packages, array($this, 'sortPackage'));
75:
76:        $message = array();
77:
78:        foreach ($packages as $package) {
79:            $options = $this->widget('Widget_Options@' . $package);
80:
81:            /** 执行升级脚本 */
82:            try {
83:                $result = call_user_func(array('Upgrade', $package), $this->db, $options);
84:                if (!empty($result)) {
85:                    $message[] = $result;
86:                }
87:            } catch (Typecho_Exception $e) {
88:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
89:                $this->response->goBack();
90:                return;
91:            }
92:
93:            list ($ver, $rev) = explode('r', $package);
94:            $ver = substr(str_replace('_', '.', $ver), 1);
95:            $rev = str_replace('_', '.', $rev);
96:
97:            /** 更新版本号 */
98:            $this->update(array('value' => 'Typecho ' . $ver . '/' . $rev),
99:            $this->db->sql()->where('name = ?', 'generator'));
100:
101:            $this->destory('Widget_Options@' . $package);
102:        }
103:
104:        /** 更新版本号 */
105:        $this->update(array('value' => 'Typecho ' . Typecho_Common::VERSION),
106:        $this->db->sql()->where('name = ?', 'generator'));
107:
108:        $this->widget('Widget_Notice')->set(empty($message) ? _t("升级已经完成") : $message,
109:        empty($message) ? 'success' : 'notice');
110:    }
danger upgrade usort第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
69:    public function upgrade()
70:    {
71:        list($prefix, $this->_currentVersion) = explode('/', $this->options->generator);
72:        $packages = get_class_methods('Upgrade');
73:        $packages = array_filter($packages, array($this, 'filterPackage'));
74:        usort($packages, array($this, 'sortPackage'));
75:
76:        $message = array();
77:
78:        foreach ($packages as $package) {
79:            $options = $this->widget('Widget_Options@' . $package);
80:
81:            /** 执行升级脚本 */
82:            try {
83:                $result = call_user_func(array('Upgrade', $package), $this->db, $options);
84:                if (!empty($result)) {
85:                    $message[] = $result;
86:                }
87:            } catch (Typecho_Exception $e) {
88:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
89:                $this->response->goBack();
90:                return;
91:            }
92:
93:            list ($ver, $rev) = explode('r', $package);
94:            $ver = substr(str_replace('_', '.', $ver), 1);
95:            $rev = str_replace('_', '.', $rev);
96:
97:            /** 更新版本号 */
98:            $this->update(array('value' => 'Typecho ' . $ver . '/' . $rev),
99:            $this->db->sql()->where('name = ?', 'generator'));
100:
101:            $this->destory('Widget_Options@' . $package);
102:        }
103:
104:        /** 更新版本号 */
105:        $this->update(array('value' => 'Typecho ' . Typecho_Common::VERSION),
106:        $this->db->sql()->where('name = ?', 'generator'));
107:
108:        $this->widget('Widget_Notice')->set(empty($message) ? _t("升级已经完成") : $message,
109:        empty($message) ? 'success' : 'notice');
110:    }
danger upgrade call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
69:    public function upgrade()
70:    {
71:        list($prefix, $this->_currentVersion) = explode('/', $this->options->generator);
72:        $packages = get_class_methods('Upgrade');
73:        $packages = array_filter($packages, array($this, 'filterPackage'));
74:        usort($packages, array($this, 'sortPackage'));
75:
76:        $message = array();
77:
78:        foreach ($packages as $package) {
79:            $options = $this->widget('Widget_Options@' . $package);
80:
81:            /** 执行升级脚本 */
82:            try {
83:                $result = call_user_func(array('Upgrade', $package), $this->db, $options);
84:                if (!empty($result)) {
85:                    $message[] = $result;
86:                }
87:            } catch (Typecho_Exception $e) {
88:                $this->widget('Widget_Notice')->set($e->getMessage(), 'error');
89:                $this->response->goBack();
90:                return;
91:            }
92:
93:            list ($ver, $rev) = explode('r', $package);
94:            $ver = substr(str_replace('_', '.', $ver), 1);
95:            $rev = str_replace('_', '.', $rev);
96:
97:            /** 更新版本号 */
98:            $this->update(array('value' => 'Typecho ' . $ver . '/' . $rev),
99:            $this->db->sql()->where('name = ?', 'generator'));
100:
101:            $this->destory('Widget_Options@' . $package);
102:        }
103:
104:        /** 更新版本号 */
105:        $this->update(array('value' => 'Typecho ' . Typecho_Common::VERSION),
106:        $this->db->sql()->where('name = ?', 'generator'));
107:
108:        $this->widget('Widget_Notice')->set(empty($message) ? _t("升级已经完成") : $message,
109:        empty($message) ? 'success' : 'notice');
110:    }

./typecho/var/Widget/Menu.php

等级 函数 说明
danger execute 动态调用方法,可能存在远程代码执行的隐患
代码
102:    public function execute()
103:    {
104:        $parentNodes = array(NULL, _t('控制台'), _t('撰写'), _t('管理'), _t('设置'));
105:
106:        $childNodes =  array(
107:        array(
108:            array(_t('登录'), _t('登录到%s', $this->options->title), 'login.php', 'visitor'),
109:            array(_t('注册'), _t('注册到%s', $this->options->title), 'register.php', 'visitor')
110:        ),
111:        array(
112:            array(_t('概要'), _t('网站概要'), 'index.php', 'subscriber'),
113:            array(_t('个人设置'), _t('个人设置'), 'profile.php', 'subscriber'),
114:            array(_t('插件'), _t('插件管理'), 'plugins.php', 'administrator'),
115:            array(array('Widget_Plugins_Config', 'getMenuTitle'), array('Widget_Plugins_Config', 'getMenuTitle'), 'options-plugin.php?config=', 'administrator', true),
116:            array(_t('外观'), _t('网站外观'), 'themes.php', 'administrator'),
117:            array(array('Widget_Themes_Files', 'getMenuTitle'), array('Widget_Themes_Files', 'getMenuTitle'), 'theme-editor.php', 'administrator', true),
118:            array(_t('设置外观'), _t('设置外观'), 'options-theme.php', 'administrator', true),
119:            array(_t('备份'), _t('备份'), 'backup.php', 'administrator'),
120:            array(_t('升级'), _t('升级程序'), 'upgrade.php', 'administrator', true),
121:            array(_t('欢迎'), _t('欢迎使用'), 'welcome.php', 'subscriber', true)
122:        ),
123:        array(
124:            array(_t('撰写文章'), _t('撰写新文章'), 'write-post.php', 'contributor'),
125:            array(array('Widget_Contents_Post_Edit', 'getMenuTitle'), array('Widget_Contents_Post_Edit', 'getMenuTitle'), 'write-post.php?cid=', 'contributor', true),
126:            array(_t('创建页面'), _t('创建新页面'), 'write-page.php', 'editor'),
127:            array(array('Widget_Contents_Page_Edit', 'getMenuTitle'), array('Widget_Contents_Page_Edit', 'getMenuTitle'), 'write-page.php?cid=', 'editor', true),
128:        ),
129:        array(
130:            array(_t('文章'), _t('管理文章'), 'manage-posts.php', 'contributor', false, 'write-post.php'),
131:            array(array('Widget_Contents_Post_Admin', 'getMenuTitle'), array('Widget_Contents_Post_Admin', 'getMenuTitle'), 'manage-posts.php?uid=', 'contributor', true),
132:            array(_t('独立页面'), _t('管理独立页面'), 'manage-pages.php', 'editor', false, 'write-page.php'),
133:            array(_t('评论'), _t('管理评论'), 'manage-comments.php', 'contributor'),
134:            array(array('Widget_Comments_Admin', 'getMenuTitle'), array('Widget_Comments_Admin', 'getMenuTitle'), 'manage-comments.php?cid=', 'contributor', true),
135:            array(_t('分类'), _t('管理分类'), 'manage-categories.php', 'editor', false, 'category.php'),
136:            array(_t('新增分类'), _t('新增分类'), 'category.php', 'editor', true),
137:            array(array('Widget_Metas_Category_Admin', 'getMenuTitle'), array('Widget_Metas_Category_Admin', 'getMenuTitle'), 'manage-categories.php?parent=', 'editor', true, array('Widget_Metas_Category_Admin', 'getAddLink')),
138:            array(array('Widget_Metas_Category_Edit', 'getMenuTitle'), array('Widget_Metas_Category_Edit', 'getMenuTitle'), 'category.php?mid=', 'editor', true),
139:            array(array('Widget_Metas_Category_Edit', 'getMenuTitle'), array('Widget_Metas_Category_Edit', 'getMenuTitle'), 'category.php?parent=', 'editor', true),
140:            array(_t('标签'), _t('管理标签'), 'manage-tags.php', 'editor'),
141:            array(array('Widget_Metas_Tag_Admin', 'getMenuTitle'), array('Widget_Metas_Tag_Admin', 'getMenuTitle'), 'manage-tags.php?mid=', 'editor', true),
142:            array(_t('文件'), _t('管理文件'), 'manage-medias.php', 'editor'),
143:            array(array('Widget_Contents_Attachment_Edit', 'getMenuTitle'), array('Widget_Contents_Attachment_Edit', 'getMenuTitle'), 'media.php?cid=', 'contributor', true),
144:            array(_t('用户'), _t('管理用户'), 'manage-users.php', 'administrator', false, 'user.php'),
145:            array(_t('新增用户'), _t('新增用户'), 'user.php', 'administrator', true),
146:            array(array('Widget_Users_Edit', 'getMenuTitle'), array('Widget_Users_Edit', 'getMenuTitle'), 'user.php?uid=', 'administrator', true),
147:        ),
148:        array(
149:            array(_t('基本'), _t('基本设置'), 'options-general.php', 'administrator'),
150:            array(_t('评论'), _t('评论设置'), 'options-discussion.php', 'administrator'),
151:            array(_t('阅读'), _t('阅读设置'), 'options-reading.php', 'administrator'),
152:            array(_t('永久链接'), _t('永久链接设置'), 'options-permalink.php', 'administrator'),
153:        ));
154:
155:        /** 获取扩展菜单 */
156:        $panelTable = unserialize($this->options->panelTable);
157:        $extendingParentMenu = empty($panelTable['parent']) ? array() : $panelTable['parent'];
158:        $extendingChildMenu = empty($panelTable['child']) ? array() : $panelTable['child'];
159:        $currentUrl = $this->request->makeUriByRequest();
160:        $adminUrl = $this->options->adminUrl;
161:        $menu = array();
162:        $defaultChildeNode = array(NULL, NULL, NULL, 'administrator', false, NULL);
163:
164:        $currentUrlParts = parse_url($currentUrl);
165:        $currentUrlParams = array();
166:        if (!empty($currentUrlParts['query'])) {
167:            parse_str($currentUrlParts['query'], $currentUrlParams);
168:        }
169:
170:        if ('/' == $currentUrlParts['path'][strlen($currentUrlParts['path']) - 1]) {
171:            $currentUrlParts['path'] .= 'index.php';
172:        }
173:
174:        foreach ($extendingParentMenu as $key => $val) {
175:            $parentNodes[10 + $key] = $val;
176:        }
177:
178:        foreach ($extendingChildMenu as $key => $val) {
179:            $childNodes[$key] = array_merge(isset($childNodes[$key]) ? $childNodes[$key] : array(), $val);
180:        }
181:
182:        foreach ($parentNodes as $key => $parentNode) {
183:            // this is a simple struct than before
184:            $children = array();
185:            $showedChildrenCount = 0;
186:            $firstUrl = NULL;
187:            
188:            foreach ($childNodes[$key] as $inKey => $childNode) {
189:                // magic merge
190:                $childNode += $defaultChildeNode;
191:                list ($name, $title, $url, $access, $hidden, $addLink) = $childNode;
192:
193:                // 保存最原始的hidden信息
194:                $orgHidden = $hidden;
195:
196:                // parse url
197:                $url = Typecho_Common::url($url, $adminUrl);
198:
199:                // compare url
200:                $urlParts = parse_url($url);
201:                $urlParams = array();
202:                if (!empty($urlParts['query'])) {
203:                    parse_str($urlParts['query'], $urlParams);
204:                }
205:
206:                $validate = true;
207:                if ($urlParts['path'] != $currentUrlParts['path']) {
208:                    $validate = false;
209:                } else {
210:                    foreach ($urlParams as $paramName => $paramValue) {
211:                        if (!isset($currentUrlParams[$paramName])) {
212:                            $validate = false;
213:                            break;
214:                        }
215:                    }
216:                }
217:                
218:                if ($validate
219:                    && basename($urlParts['path']) == 'extending.php'
220:                    && !empty($currentUrlParams['panel']) && !empty($urlParams['panel'])
221:                    && $urlParams['panel'] != $currentUrlParams['panel']){
222:                    $validate = false;
223:                }
224:                
225:                if ($hidden && $validate) {
226:                    $hidden = false;
227:                }
228:
229:                if (!$hidden && !$this->user->pass($access, true)) {
230:                    $hidden = true;
231:                }
232:
233:                if (!$hidden) {
234:                    $showedChildrenCount ++;
235:
236:                    if (empty($firstUrl)) {
237:                        $firstUrl = $url;
238:                    }
239:
240:                    if (is_array($name)) {
241:                        list($widget, $method) = $name;
242:                        $name = Typecho_Widget::widget($widget)->$method();
243:                    }
244:                    
245:                    if (is_array($title)) {
246:                        list($widget, $method) = $title;
247:                        $title = Typecho_Widget::widget($widget)->$method();
248:                    }
249:
250:                    if (is_array($addLink)) {
251:                        list($widget, $method) = $addLink;
252:                        $addLink = Typecho_Widget::widget($widget)->$method();
253:                    }
254:                }
255:
256:                if ($validate) {
257:                    if ('visitor' != $access) {
258:                        $this->user->pass($access);
259:                    }
260:                    
261:                    $this->_currentParent = $key;
262:                    $this->_currentChild = $inKey;
263:                    $this->title = $title;
264:                    $this->addLink = $addLink ? Typecho_Common::url($addLink, $adminUrl) : NULL;
265:                } 
266:
267:                $children[$inKey] = array(
268:                    $name,
269:                    $title,
270:                    $url,
271:                    $access,
272:                    $hidden,
273:                    $addLink,
274:                    $orgHidden
275:                );
276:            }
277:
278:            $menu[$key] = array($parentNode, $showedChildrenCount > 0, $firstUrl,$children);
279:        }
280:
281:        $this->_menu = $menu;
282:        $this->_currentUrl = $currentUrl;
283:    }
danger execute 动态调用方法,可能存在远程代码执行的隐患
代码
102:    public function execute()
103:    {
104:        $parentNodes = array(NULL, _t('控制台'), _t('撰写'), _t('管理'), _t('设置'));
105:
106:        $childNodes =  array(
107:        array(
108:            array(_t('登录'), _t('登录到%s', $this->options->title), 'login.php', 'visitor'),
109:            array(_t('注册'), _t('注册到%s', $this->options->title), 'register.php', 'visitor')
110:        ),
111:        array(
112:            array(_t('概要'), _t('网站概要'), 'index.php', 'subscriber'),
113:            array(_t('个人设置'), _t('个人设置'), 'profile.php', 'subscriber'),
114:            array(_t('插件'), _t('插件管理'), 'plugins.php', 'administrator'),
115:            array(array('Widget_Plugins_Config', 'getMenuTitle'), array('Widget_Plugins_Config', 'getMenuTitle'), 'options-plugin.php?config=', 'administrator', true),
116:            array(_t('外观'), _t('网站外观'), 'themes.php', 'administrator'),
117:            array(array('Widget_Themes_Files', 'getMenuTitle'), array('Widget_Themes_Files', 'getMenuTitle'), 'theme-editor.php', 'administrator', true),
118:            array(_t('设置外观'), _t('设置外观'), 'options-theme.php', 'administrator', true),
119:            array(_t('备份'), _t('备份'), 'backup.php', 'administrator'),
120:            array(_t('升级'), _t('升级程序'), 'upgrade.php', 'administrator', true),
121:            array(_t('欢迎'), _t('欢迎使用'), 'welcome.php', 'subscriber', true)
122:        ),
123:        array(
124:            array(_t('撰写文章'), _t('撰写新文章'), 'write-post.php', 'contributor'),
125:            array(array('Widget_Contents_Post_Edit', 'getMenuTitle'), array('Widget_Contents_Post_Edit', 'getMenuTitle'), 'write-post.php?cid=', 'contributor', true),
126:            array(_t('创建页面'), _t('创建新页面'), 'write-page.php', 'editor'),
127:            array(array('Widget_Contents_Page_Edit', 'getMenuTitle'), array('Widget_Contents_Page_Edit', 'getMenuTitle'), 'write-page.php?cid=', 'editor', true),
128:        ),
129:        array(
130:            array(_t('文章'), _t('管理文章'), 'manage-posts.php', 'contributor', false, 'write-post.php'),
131:            array(array('Widget_Contents_Post_Admin', 'getMenuTitle'), array('Widget_Contents_Post_Admin', 'getMenuTitle'), 'manage-posts.php?uid=', 'contributor', true),
132:            array(_t('独立页面'), _t('管理独立页面'), 'manage-pages.php', 'editor', false, 'write-page.php'),
133:            array(_t('评论'), _t('管理评论'), 'manage-comments.php', 'contributor'),
134:            array(array('Widget_Comments_Admin', 'getMenuTitle'), array('Widget_Comments_Admin', 'getMenuTitle'), 'manage-comments.php?cid=', 'contributor', true),
135:            array(_t('分类'), _t('管理分类'), 'manage-categories.php', 'editor', false, 'category.php'),
136:            array(_t('新增分类'), _t('新增分类'), 'category.php', 'editor', true),
137:            array(array('Widget_Metas_Category_Admin', 'getMenuTitle'), array('Widget_Metas_Category_Admin', 'getMenuTitle'), 'manage-categories.php?parent=', 'editor', true, array('Widget_Metas_Category_Admin', 'getAddLink')),
138:            array(array('Widget_Metas_Category_Edit', 'getMenuTitle'), array('Widget_Metas_Category_Edit', 'getMenuTitle'), 'category.php?mid=', 'editor', true),
139:            array(array('Widget_Metas_Category_Edit', 'getMenuTitle'), array('Widget_Metas_Category_Edit', 'getMenuTitle'), 'category.php?parent=', 'editor', true),
140:            array(_t('标签'), _t('管理标签'), 'manage-tags.php', 'editor'),
141:            array(array('Widget_Metas_Tag_Admin', 'getMenuTitle'), array('Widget_Metas_Tag_Admin', 'getMenuTitle'), 'manage-tags.php?mid=', 'editor', true),
142:            array(_t('文件'), _t('管理文件'), 'manage-medias.php', 'editor'),
143:            array(array('Widget_Contents_Attachment_Edit', 'getMenuTitle'), array('Widget_Contents_Attachment_Edit', 'getMenuTitle'), 'media.php?cid=', 'contributor', true),
144:            array(_t('用户'), _t('管理用户'), 'manage-users.php', 'administrator', false, 'user.php'),
145:            array(_t('新增用户'), _t('新增用户'), 'user.php', 'administrator', true),
146:            array(array('Widget_Users_Edit', 'getMenuTitle'), array('Widget_Users_Edit', 'getMenuTitle'), 'user.php?uid=', 'administrator', true),
147:        ),
148:        array(
149:            array(_t('基本'), _t('基本设置'), 'options-general.php', 'administrator'),
150:            array(_t('评论'), _t('评论设置'), 'options-discussion.php', 'administrator'),
151:            array(_t('阅读'), _t('阅读设置'), 'options-reading.php', 'administrator'),
152:            array(_t('永久链接'), _t('永久链接设置'), 'options-permalink.php', 'administrator'),
153:        ));
154:
155:        /** 获取扩展菜单 */
156:        $panelTable = unserialize($this->options->panelTable);
157:        $extendingParentMenu = empty($panelTable['parent']) ? array() : $panelTable['parent'];
158:        $extendingChildMenu = empty($panelTable['child']) ? array() : $panelTable['child'];
159:        $currentUrl = $this->request->makeUriByRequest();
160:        $adminUrl = $this->options->adminUrl;
161:        $menu = array();
162:        $defaultChildeNode = array(NULL, NULL, NULL, 'administrator', false, NULL);
163:
164:        $currentUrlParts = parse_url($currentUrl);
165:        $currentUrlParams = array();
166:        if (!empty($currentUrlParts['query'])) {
167:            parse_str($currentUrlParts['query'], $currentUrlParams);
168:        }
169:
170:        if ('/' == $currentUrlParts['path'][strlen($currentUrlParts['path']) - 1]) {
171:            $currentUrlParts['path'] .= 'index.php';
172:        }
173:
174:        foreach ($extendingParentMenu as $key => $val) {
175:            $parentNodes[10 + $key] = $val;
176:        }
177:
178:        foreach ($extendingChildMenu as $key => $val) {
179:            $childNodes[$key] = array_merge(isset($childNodes[$key]) ? $childNodes[$key] : array(), $val);
180:        }
181:
182:        foreach ($parentNodes as $key => $parentNode) {
183:            // this is a simple struct than before
184:            $children = array();
185:            $showedChildrenCount = 0;
186:            $firstUrl = NULL;
187:            
188:            foreach ($childNodes[$key] as $inKey => $childNode) {
189:                // magic merge
190:                $childNode += $defaultChildeNode;
191:                list ($name, $title, $url, $access, $hidden, $addLink) = $childNode;
192:
193:                // 保存最原始的hidden信息
194:                $orgHidden = $hidden;
195:
196:                // parse url
197:                $url = Typecho_Common::url($url, $adminUrl);
198:
199:                // compare url
200:                $urlParts = parse_url($url);
201:                $urlParams = array();
202:                if (!empty($urlParts['query'])) {
203:                    parse_str($urlParts['query'], $urlParams);
204:                }
205:
206:                $validate = true;
207:                if ($urlParts['path'] != $currentUrlParts['path']) {
208:                    $validate = false;
209:                } else {
210:                    foreach ($urlParams as $paramName => $paramValue) {
211:                        if (!isset($currentUrlParams[$paramName])) {
212:                            $validate = false;
213:                            break;
214:                        }
215:                    }
216:                }
217:                
218:                if ($validate
219:                    && basename($urlParts['path']) == 'extending.php'
220:                    && !empty($currentUrlParams['panel']) && !empty($urlParams['panel'])
221:                    && $urlParams['panel'] != $currentUrlParams['panel']){
222:                    $validate = false;
223:                }
224:                
225:                if ($hidden && $validate) {
226:                    $hidden = false;
227:                }
228:
229:                if (!$hidden && !$this->user->pass($access, true)) {
230:                    $hidden = true;
231:                }
232:
233:                if (!$hidden) {
234:                    $showedChildrenCount ++;
235:
236:                    if (empty($firstUrl)) {
237:                        $firstUrl = $url;
238:                    }
239:
240:                    if (is_array($name)) {
241:                        list($widget, $method) = $name;
242:                        $name = Typecho_Widget::widget($widget)->$method();
243:                    }
244:                    
245:                    if (is_array($title)) {
246:                        list($widget, $method) = $title;
247:                        $title = Typecho_Widget::widget($widget)->$method();
248:                    }
249:
250:                    if (is_array($addLink)) {
251:                        list($widget, $method) = $addLink;
252:                        $addLink = Typecho_Widget::widget($widget)->$method();
253:                    }
254:                }
255:
256:                if ($validate) {
257:                    if ('visitor' != $access) {
258:                        $this->user->pass($access);
259:                    }
260:                    
261:                    $this->_currentParent = $key;
262:                    $this->_currentChild = $inKey;
263:                    $this->title = $title;
264:                    $this->addLink = $addLink ? Typecho_Common::url($addLink, $adminUrl) : NULL;
265:                } 
266:
267:                $children[$inKey] = array(
268:                    $name,
269:                    $title,
270:                    $url,
271:                    $access,
272:                    $hidden,
273:                    $addLink,
274:                    $orgHidden
275:                );
276:            }
277:
278:            $menu[$key] = array($parentNode, $showedChildrenCount > 0, $firstUrl,$children);
279:        }
280:
281:        $this->_menu = $menu;
282:        $this->_currentUrl = $currentUrl;
283:    }
danger execute 动态调用方法,可能存在远程代码执行的隐患
代码
102:    public function execute()
103:    {
104:        $parentNodes = array(NULL, _t('控制台'), _t('撰写'), _t('管理'), _t('设置'));
105:
106:        $childNodes =  array(
107:        array(
108:            array(_t('登录'), _t('登录到%s', $this->options->title), 'login.php', 'visitor'),
109:            array(_t('注册'), _t('注册到%s', $this->options->title), 'register.php', 'visitor')
110:        ),
111:        array(
112:            array(_t('概要'), _t('网站概要'), 'index.php', 'subscriber'),
113:            array(_t('个人设置'), _t('个人设置'), 'profile.php', 'subscriber'),
114:            array(_t('插件'), _t('插件管理'), 'plugins.php', 'administrator'),
115:            array(array('Widget_Plugins_Config', 'getMenuTitle'), array('Widget_Plugins_Config', 'getMenuTitle'), 'options-plugin.php?config=', 'administrator', true),
116:            array(_t('外观'), _t('网站外观'), 'themes.php', 'administrator'),
117:            array(array('Widget_Themes_Files', 'getMenuTitle'), array('Widget_Themes_Files', 'getMenuTitle'), 'theme-editor.php', 'administrator', true),
118:            array(_t('设置外观'), _t('设置外观'), 'options-theme.php', 'administrator', true),
119:            array(_t('备份'), _t('备份'), 'backup.php', 'administrator'),
120:            array(_t('升级'), _t('升级程序'), 'upgrade.php', 'administrator', true),
121:            array(_t('欢迎'), _t('欢迎使用'), 'welcome.php', 'subscriber', true)
122:        ),
123:        array(
124:            array(_t('撰写文章'), _t('撰写新文章'), 'write-post.php', 'contributor'),
125:            array(array('Widget_Contents_Post_Edit', 'getMenuTitle'), array('Widget_Contents_Post_Edit', 'getMenuTitle'), 'write-post.php?cid=', 'contributor', true),
126:            array(_t('创建页面'), _t('创建新页面'), 'write-page.php', 'editor'),
127:            array(array('Widget_Contents_Page_Edit', 'getMenuTitle'), array('Widget_Contents_Page_Edit', 'getMenuTitle'), 'write-page.php?cid=', 'editor', true),
128:        ),
129:        array(
130:            array(_t('文章'), _t('管理文章'), 'manage-posts.php', 'contributor', false, 'write-post.php'),
131:            array(array('Widget_Contents_Post_Admin', 'getMenuTitle'), array('Widget_Contents_Post_Admin', 'getMenuTitle'), 'manage-posts.php?uid=', 'contributor', true),
132:            array(_t('独立页面'), _t('管理独立页面'), 'manage-pages.php', 'editor', false, 'write-page.php'),
133:            array(_t('评论'), _t('管理评论'), 'manage-comments.php', 'contributor'),
134:            array(array('Widget_Comments_Admin', 'getMenuTitle'), array('Widget_Comments_Admin', 'getMenuTitle'), 'manage-comments.php?cid=', 'contributor', true),
135:            array(_t('分类'), _t('管理分类'), 'manage-categories.php', 'editor', false, 'category.php'),
136:            array(_t('新增分类'), _t('新增分类'), 'category.php', 'editor', true),
137:            array(array('Widget_Metas_Category_Admin', 'getMenuTitle'), array('Widget_Metas_Category_Admin', 'getMenuTitle'), 'manage-categories.php?parent=', 'editor', true, array('Widget_Metas_Category_Admin', 'getAddLink')),
138:            array(array('Widget_Metas_Category_Edit', 'getMenuTitle'), array('Widget_Metas_Category_Edit', 'getMenuTitle'), 'category.php?mid=', 'editor', true),
139:            array(array('Widget_Metas_Category_Edit', 'getMenuTitle'), array('Widget_Metas_Category_Edit', 'getMenuTitle'), 'category.php?parent=', 'editor', true),
140:            array(_t('标签'), _t('管理标签'), 'manage-tags.php', 'editor'),
141:            array(array('Widget_Metas_Tag_Admin', 'getMenuTitle'), array('Widget_Metas_Tag_Admin', 'getMenuTitle'), 'manage-tags.php?mid=', 'editor', true),
142:            array(_t('文件'), _t('管理文件'), 'manage-medias.php', 'editor'),
143:            array(array('Widget_Contents_Attachment_Edit', 'getMenuTitle'), array('Widget_Contents_Attachment_Edit', 'getMenuTitle'), 'media.php?cid=', 'contributor', true),
144:            array(_t('用户'), _t('管理用户'), 'manage-users.php', 'administrator', false, 'user.php'),
145:            array(_t('新增用户'), _t('新增用户'), 'user.php', 'administrator', true),
146:            array(array('Widget_Users_Edit', 'getMenuTitle'), array('Widget_Users_Edit', 'getMenuTitle'), 'user.php?uid=', 'administrator', true),
147:        ),
148:        array(
149:            array(_t('基本'), _t('基本设置'), 'options-general.php', 'administrator'),
150:            array(_t('评论'), _t('评论设置'), 'options-discussion.php', 'administrator'),
151:            array(_t('阅读'), _t('阅读设置'), 'options-reading.php', 'administrator'),
152:            array(_t('永久链接'), _t('永久链接设置'), 'options-permalink.php', 'administrator'),
153:        ));
154:
155:        /** 获取扩展菜单 */
156:        $panelTable = unserialize($this->options->panelTable);
157:        $extendingParentMenu = empty($panelTable['parent']) ? array() : $panelTable['parent'];
158:        $extendingChildMenu = empty($panelTable['child']) ? array() : $panelTable['child'];
159:        $currentUrl = $this->request->makeUriByRequest();
160:        $adminUrl = $this->options->adminUrl;
161:        $menu = array();
162:        $defaultChildeNode = array(NULL, NULL, NULL, 'administrator', false, NULL);
163:
164:        $currentUrlParts = parse_url($currentUrl);
165:        $currentUrlParams = array();
166:        if (!empty($currentUrlParts['query'])) {
167:            parse_str($currentUrlParts['query'], $currentUrlParams);
168:        }
169:
170:        if ('/' == $currentUrlParts['path'][strlen($currentUrlParts['path']) - 1]) {
171:            $currentUrlParts['path'] .= 'index.php';
172:        }
173:
174:        foreach ($extendingParentMenu as $key => $val) {
175:            $parentNodes[10 + $key] = $val;
176:        }
177:
178:        foreach ($extendingChildMenu as $key => $val) {
179:            $childNodes[$key] = array_merge(isset($childNodes[$key]) ? $childNodes[$key] : array(), $val);
180:        }
181:
182:        foreach ($parentNodes as $key => $parentNode) {
183:            // this is a simple struct than before
184:            $children = array();
185:            $showedChildrenCount = 0;
186:            $firstUrl = NULL;
187:            
188:            foreach ($childNodes[$key] as $inKey => $childNode) {
189:                // magic merge
190:                $childNode += $defaultChildeNode;
191:                list ($name, $title, $url, $access, $hidden, $addLink) = $childNode;
192:
193:                // 保存最原始的hidden信息
194:                $orgHidden = $hidden;
195:
196:                // parse url
197:                $url = Typecho_Common::url($url, $adminUrl);
198:
199:                // compare url
200:                $urlParts = parse_url($url);
201:                $urlParams = array();
202:                if (!empty($urlParts['query'])) {
203:                    parse_str($urlParts['query'], $urlParams);
204:                }
205:
206:                $validate = true;
207:                if ($urlParts['path'] != $currentUrlParts['path']) {
208:                    $validate = false;
209:                } else {
210:                    foreach ($urlParams as $paramName => $paramValue) {
211:                        if (!isset($currentUrlParams[$paramName])) {
212:                            $validate = false;
213:                            break;
214:                        }
215:                    }
216:                }
217:                
218:                if ($validate
219:                    && basename($urlParts['path']) == 'extending.php'
220:                    && !empty($currentUrlParams['panel']) && !empty($urlParams['panel'])
221:                    && $urlParams['panel'] != $currentUrlParams['panel']){
222:                    $validate = false;
223:                }
224:                
225:                if ($hidden && $validate) {
226:                    $hidden = false;
227:                }
228:
229:                if (!$hidden && !$this->user->pass($access, true)) {
230:                    $hidden = true;
231:                }
232:
233:                if (!$hidden) {
234:                    $showedChildrenCount ++;
235:
236:                    if (empty($firstUrl)) {
237:                        $firstUrl = $url;
238:                    }
239:
240:                    if (is_array($name)) {
241:                        list($widget, $method) = $name;
242:                        $name = Typecho_Widget::widget($widget)->$method();
243:                    }
244:                    
245:                    if (is_array($title)) {
246:                        list($widget, $method) = $title;
247:                        $title = Typecho_Widget::widget($widget)->$method();
248:                    }
249:
250:                    if (is_array($addLink)) {
251:                        list($widget, $method) = $addLink;
252:                        $addLink = Typecho_Widget::widget($widget)->$method();
253:                    }
254:                }
255:
256:                if ($validate) {
257:                    if ('visitor' != $access) {
258:                        $this->user->pass($access);
259:                    }
260:                    
261:                    $this->_currentParent = $key;
262:                    $this->_currentChild = $inKey;
263:                    $this->title = $title;
264:                    $this->addLink = $addLink ? Typecho_Common::url($addLink, $adminUrl) : NULL;
265:                } 
266:
267:                $children[$inKey] = array(
268:                    $name,
269:                    $title,
270:                    $url,
271:                    $access,
272:                    $hidden,
273:                    $addLink,
274:                    $orgHidden
275:                );
276:            }
277:
278:            $menu[$key] = array($parentNode, $showedChildrenCount > 0, $firstUrl,$children);
279:        }
280:
281:        $this->_menu = $menu;
282:        $this->_currentUrl = $currentUrl;
283:    }

./typecho/var/Widget/Users/Profile.php

等级 函数 说明
danger personalForm 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
159:    public function personalForm($pluginName, $className, $pluginFileName, &$group)
160:    {
161:        /** 构建表格 */
162:        $form = new Typecho_Widget_Helper_Form($this->security->getIndex('/action/users-profile'),
163:        Typecho_Widget_Helper_Form::POST_METHOD);
164:        $form->setAttribute('name', $pluginName);
165:        $form->setAttribute('id', $pluginName);
166:
167:        require_once $pluginFileName;
168:        $group = call_user_func(array($className, 'personalConfig'), $form);
169:        $group = $group ? $group : 'subscriber';
170:
171:        $options = $this->options->personalPlugin($pluginName);
172:
173:        if (!empty($options)) {
174:            foreach ($options as $key => $val) {
175:                $form->getInput($key)->value($val);
176:            }
177:        }
178:
179:        $form->addItem(new Typecho_Widget_Helper_Form_Element_Hidden('do', NULL, 'personal'));
180:        $form->addItem(new Typecho_Widget_Helper_Form_Element_Hidden('plugin', NULL, $pluginName));
181:        $submit = new Typecho_Widget_Helper_Form_Element_Submit('submit', NULL, _t('保存设置'));
182:        $submit->input->setAttribute('class', 'btn primary');
183:        $form->addItem($submit);
184:        return $form;
185:    }
danger personalForm call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
159:    public function personalForm($pluginName, $className, $pluginFileName, &$group)
160:    {
161:        /** 构建表格 */
162:        $form = new Typecho_Widget_Helper_Form($this->security->getIndex('/action/users-profile'),
163:        Typecho_Widget_Helper_Form::POST_METHOD);
164:        $form->setAttribute('name', $pluginName);
165:        $form->setAttribute('id', $pluginName);
166:
167:        require_once $pluginFileName;
168:        $group = call_user_func(array($className, 'personalConfig'), $form);
169:        $group = $group ? $group : 'subscriber';
170:
171:        $options = $this->options->personalPlugin($pluginName);
172:
173:        if (!empty($options)) {
174:            foreach ($options as $key => $val) {
175:                $form->getInput($key)->value($val);
176:            }
177:        }
178:
179:        $form->addItem(new Typecho_Widget_Helper_Form_Element_Hidden('do', NULL, 'personal'));
180:        $form->addItem(new Typecho_Widget_Helper_Form_Element_Hidden('plugin', NULL, $pluginName));
181:        $submit = new Typecho_Widget_Helper_Form_Element_Submit('submit', NULL, _t('保存设置'));
182:        $submit->input->setAttribute('class', 'btn primary');
183:        $form->addItem($submit);
184:        return $form;
185:    }
danger personalConfigHandle call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
412:    public function personalConfigHandle($className, array $settings)
413:    {
414:        if (method_exists($className, 'personalConfigHandle')) {
415:            call_user_func(array($className, 'personalConfigHandle'), $settings, false);
416:            return true;
417:        }
418:
419:        return false;
420:    }

./typecho/var/Widget/Users/Admin.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
79:    public function execute()
80:    {
81:        $this->parameter->setDefault('pageSize=20');
82:        $select = $this->select();
83:        $this->_currentPage = $this->request->get('page', 1);
84:
85:        /** 过滤标题 */
86:        if (NULL != ($keywords = $this->request->keywords)) {
87:            $select->where('name LIKE ? OR screenName LIKE ?',
88:            '%' . Typecho_Common::filterSearchQuery($keywords) . '%',
89:            '%' . Typecho_Common::filterSearchQuery($keywords) . '%');
90:        }
91:
92:        $this->_countSql = clone $select;
93:
94:        $select->order('table.users.uid', Typecho_Db::SORT_ASC)
95:        ->page($this->_currentPage, $this->parameter->pageSize);
96:
97:        $this->db->fetchAll($select, array($this, 'push'));
98:    }

./typecho/var/Widget/Options.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
342:    public function execute()
343:    {
344:        $this->db->fetchAll($this->db->select()->from('table.options')
345:        ->where('user = 0'), array($this, 'push'));
346:        
347:        /** 支持皮肤变量重载 */
348:        if (!empty($this->row['theme:' . $this->row['theme']])) {
349:            $themeOptions = NULL;
350:        
351:            /** 解析变量 */
352:            if ($themeOptions = unserialize($this->row['theme:' . $this->row['theme']])) {
353:                /** 覆盖变量 */
354:                $this->row = array_merge($this->row, $themeOptions);
355:            }
356:        }
357:        
358:        $this->stack[] = &$this->row;
359:
360:        /** 初始化站点信息 */
361:        if (defined('__TYPECHO_SITE_URL__')) {
362:            $this->siteUrl = __TYPECHO_SITE_URL__;
363:        }
364:
365:        $this->originalSiteUrl = $this->siteUrl;
366:        $this->siteUrl = Typecho_Common::url(NULL, $this->siteUrl);
367:        $this->plugins = unserialize($this->plugins);
368:
369:        /** 动态判断皮肤目录 */
370:        $this->theme = is_dir($this->themeFile($this->theme)) ? $this->theme : 'default';
371:
372:        /** 动态获取根目录 */
373:        $this->rootUrl = $this->request->getRequestRoot();
374:        if (defined('__TYPECHO_ADMIN__')) {
375:            /** 识别在admin目录中的情况 */
376:            $adminDir = '/' . trim(defined('__TYPECHO_ADMIN_DIR__') ? __TYPECHO_ADMIN_DIR__ : '/admin/', '/');
377:            $this->rootUrl = substr($this->rootUrl, 0, - strlen($adminDir));
378:        }
379:
380:        /** 增加对SSL连接的支持 */
381:        if ($this->request->isSecure() && 0 === strpos($this->siteUrl, 'http://')) {
382:            $this->siteUrl = substr_replace($this->siteUrl, 'https', 0, 4);
383:        }
384:
385:        /** 自动初始化路由表 */
386:        $this->routingTable = unserialize($this->routingTable);
387:        if (!isset($this->routingTable[0])) {
388:            /** 解析路由并缓存 */
389:            $parser = new Typecho_Router_Parser($this->routingTable);
390:            $parsedRoutingTable = $parser->parse();
391:            $this->routingTable = array_merge(array($parsedRoutingTable), $this->routingTable);
392:            $this->db->query($this->db->update('table.options')->rows(array('value' => serialize($this->routingTable)))
393:            ->where('name = ?', 'routingTable'));
394:        }
395:    }

./typecho/var/Widget/Metas/Category/List.php

等级 函数 说明
danger __construct array_map第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
87:    public function __construct($request, $response, $params = NULL)
88:    {
89:        parent::__construct($request, $response, $params);
90:        $this->parameter->setDefault('ignore=0&current=');
91:
92:        $select = $this->select()->where('type = ?', 'category');
93:        if ($this->parameter->ignore) {
94:            $select->where('mid <> ?', $this->parameter->ignore);
95:        }
96:
97:        $categories = $this->db->fetchAll($select->order('table.metas.order', Typecho_Db::SORT_ASC));
98:        foreach ($categories as $category) {
99:            $category['levels'] = 0;
100:            $this->_map[$category['mid']] = $category;
101:        }
102:
103:        // 读取数据
104:        foreach ($this->_map as $mid => $category) {
105:            $parent = $category['parent'];
106:
107:            if (0 != $parent && isset($this->_map[$parent])) {
108:                $this->_treeViewCategories[$parent][] = $mid;
109:            } else {
110:                $this->_top[] = $mid;
111:            }
112:        }
113:        
114:        // 预处理深度
115:        $this->levelWalkCallback($this->_top);
116:        $this->_map = array_map(array($this, 'filter'), $this->_map);
117:    }

./typecho/var/Widget/Metas/Tag/Cloud.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
29:    public function execute()
30:    {
31:        $this->parameter->setDefault(array('sort' => 'count', 'ignoreZeroCount' => false, 'desc' => true, 'limit' => 0));
32:        $select = $this->select()->where('type = ?', 'tag')->order($this->parameter->sort,
33:        $this->parameter->desc ? Typecho_Db::SORT_DESC : Typecho_Db::SORT_ASC);
34:
35:        /** 忽略零数量 */
36:        if ($this->parameter->ignoreZeroCount) {
37:            $select->where('count > 0');
38:        }
39:
40:        /** 总数限制 */
41:        if ($this->parameter->limit) {
42:            $select->limit($this->parameter->limit);
43:        }
44:
45:        $this->db->fetchAll($select, array($this, 'push'));
46:    }
warning split call_user_func_array第0个参数,请使用闭包函数
代码
55:    public function split()
56:    {
57:        $args = func_get_args();
58:        array_unshift($args, $this->count);
59:        echo call_user_func_array(array('Typecho_Common', 'splitByCount'), $args);
60:    }

./typecho/var/Widget/Metas/Tag/Admin.php

等级 函数 说明
danger execute fetchAll方法第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
29:    public function execute()
30:    {
31:        $select = $this->select()->where('type = ?', 'tag')->order('mid', Typecho_Db::SORT_DESC);
32:        $this->db->fetchAll($select, array($this, 'push'));
33:    }

./typecho/var/Widget/Themes/Config.php

等级 函数 说明
danger isExists 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
44:    public static function isExists()
45:    {
46:        $options = Typecho_Widget::widget('Widget_Options');
47:        $configFile = $options->themeFile($options->theme, 'functions.php');
48:
49:        if (file_exists($configFile)) {
50:            require_once $configFile;
51:            
52:            if (function_exists('themeConfig')) {
53:                return true;
54:            }
55:        }
56:        
57:        return false;
58:    }

./typecho/var/Widget/Themes/List.php

等级 函数 说明
danger execute array_filter第1个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
50:    public function execute()
51:    {
52:        $themes = $this->getThemes();
53:
54:        if ($themes) {
55:            $options = $this->widget('Widget_Options');
56:            $siteUrl = $options->siteUrl;
57:            $adminUrl = $options->adminUrl;
58:            $activated  = 0;
59:            $result = array();
60:
61:            foreach ($themes as $key => $theme) {
62:                $themeFile = $theme . '/index.php';
63:                if (file_exists($themeFile)) {
64:                    $info = Typecho_Plugin::parseInfo($themeFile);
65:                    $info['name'] = $this->getTheme($theme, $key);
66:
67:                    if ($info['activated'] = ($options->theme == $info['name'])) {
68:                        $activated = $key;
69:                    }
70:
71:                    $screen = array_filter(glob($theme . '/*'), function ($path) {
72:                        return preg_match("/screenshot\.(jpg|png|gif|bmp|jpeg)$/i", $path);
73:                    });
74:
75:                    if ($screen) {
76:                        $info['screen'] = $options->themeUrl(basename(current($screen)), $info['name']);
77:                    } else {
78:                        $info['screen'] = Typecho_Common::url('noscreen.png', $options->adminStaticUrl('img'));
79:                    }
80:
81:                    $result[$key] = $info;
82:                }
83:            }
84:
85:            $clone = $result[$activated];
86:            unset($result[$activated]);
87:            array_unshift($result, $clone);
88:            array_filter($result, array($this, 'push'));
89:        }
90:    }

./typecho/var/Widget/Themes/Edit.php

等级 函数 说明
danger changeTheme 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
32:    public function changeTheme($theme)
33:    {
34:        $theme = trim($theme, './');
35:        if (is_dir($this->options->themeFile($theme))) {
36:            /** 删除原外观设置信息 */
37:            $this->delete($this->db->sql()->where('name = ?', 'theme:' . $this->options->theme));
38:
39:            $this->update(array('value' => $theme), $this->db->sql()->where('name = ?', 'theme'));
40:
41:            /** 解除首页关联 */
42:            if (0 === strpos($this->options->frontPage, 'file:')) {
43:                $this->update(array('value' => 'recent'), $this->db->sql()->where('name = ?', 'frontPage'));
44:            }
45:            
46:            $configFile = $this->options->themeFile($theme, 'functions.php');
47:            
48:            if (file_exists($configFile)) {
49:                require_once $configFile;
50:                
51:                if (function_exists('themeConfig')) {
52:                    $form = new Typecho_Widget_Helper_Form();
53:                    themeConfig($form);
54:                    $options = $form->getValues();
55:
56:                    if ($options && !$this->configHandle($options, true)) {
57:                        $this->insert(array(
58:                            'name'  =>  'theme:' . $theme,
59:                            'value' =>  serialize($options),
60:                            'user'  =>  0
61:                        ));
62:                    }
63:                }
64:            }
65:
66:            $this->widget('Widget_Notice')->highlight('theme-' . $theme);
67:            $this->widget('Widget_Notice')->set(_t("外观已经改变"), 'success');
68:            $this->response->goBack();
69:        } else {
70:            throw new Typecho_Widget_Exception(_t('您选择的风格不存在'));
71:        }
72:    }

./typecho/var/Widget/Feedback.php

等级 函数 说明
danger action 动态调用方法,可能存在远程代码执行的隐患
代码
268:    public function action()
269:    {
270:        /** 回调方法 */
271:        $callback = $this->request->type;
272:        $this->_content = Typecho_Router::match($this->request->permalink);
273:
274:        /** 判断内容是否存在 */
275:        if (false !== $this->_content && $this->_content instanceof Widget_Archive &&
276:        $this->_content->have() && $this->_content->is('single') &&
277:        in_array($callback, array('comment', 'trackback'))) {
278:
279:            /** 如果文章不允许反馈 */
280:            if ('comment' == $callback) {
281:                /** 评论关闭 */
282:                if (!$this->_content->allow('comment')) {
283:                    throw new Typecho_Widget_Exception(_t('对不起,此内容的反馈被禁止.'), 403);
284:                }
285:                
286:                /** 检查来源 */
287:                if ($this->options->commentsCheckReferer && 'false' != $this->parameter->checkReferer) {
288:                    $referer = $this->request->getReferer();
289:
290:                    if (empty($referer)) {
291:                        throw new Typecho_Widget_Exception(_t('评论来源页错误.'), 403);
292:                    }
293:
294:                    $refererPart = parse_url($referer);
295:                    $currentPart = parse_url($this->_content->permalink);
296:
297:                    if ($refererPart['host'] != $currentPart['host'] ||
298:                    0 !== strpos($refererPart['path'], $currentPart['path'])) {
299:                        
300:                        //自定义首页支持
301:                        if ('page:' . $this->_content->cid == $this->options->frontPage) {
302:                            $currentPart = parse_url(rtrim($this->options->siteUrl, '/') . '/');
303:                            
304:                            if ($refererPart['host'] != $currentPart['host'] ||
305:                            0 !== strpos($refererPart['path'], $currentPart['path'])) {
306:                                throw new Typecho_Widget_Exception(_t('评论来源页错误.'), 403);
307:                            }
308:                        } else {
309:                            throw new Typecho_Widget_Exception(_t('评论来源页错误.'), 403);
310:                        }
311:                    }
312:                }
313:
314:                /** 检查ip评论间隔 */
315:                if (!$this->user->pass('editor', true) && $this->_content->authorId != $this->user->uid &&
316:                    $this->options->commentsPostIntervalEnable) {
317:
318:                    $latestComment = $this->db->fetchRow($this->db->select('created')->from('table.comments')
319:                    ->where('cid = ? AND ip = ?', $this->_content->cid, $this->request->getIp())
320:                    ->order('created', Typecho_Db::SORT_DESC)
321:                    ->limit(1));
322:
323:                    if ($latestComment && ($this->options->gmtTime - $latestComment['created'] > 0 &&
324:                    $this->options->gmtTime - $latestComment['created'] < $this->options->commentsPostInterval)) {
325:                        throw new Typecho_Widget_Exception(_t('对不起, 您的发言过于频繁, 请稍侯再次发布.'), 403);
326:                    }
327:                }
328:            }
329:
330:            /** 如果文章不允许引用 */
331:            if ('trackback' == $callback && !$this->_content->allow('ping')) {
332:                throw new Typecho_Widget_Exception(_t('对不起,此内容的引用被禁止.'), 403);
333:            }
334:
335:            /** 调用函数 */
336:            $this->$callback();
337:        } else {
338:            throw new Typecho_Widget_Exception(_t('找不到内容'), 404);
339:        }
340:    }

./typecho/var/Json.php

等级 函数 说明
danger _reduce_string preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
105:    private static function _reduce_string($str)
106:    {
107:        $str = preg_replace(array(
108:                '#^\s*//(.+)$#m',
109:                '#^\s*/\*(.+)\*/#Us',
110:                '#/\*(.+)\*/\s*$#Us'
111:            ), '', $str);
112:        return trim($str);
113:    }
warning _encode array_map第0个参数,请使用闭包函数
代码
122:    public static function _encode($var)
123:    {
124:        switch (gettype($var)) {
125:            case 'boolean':
126:                return $var ? 'true' : 'false';
127:
128:            case 'NULL':
129:                return 'null';
130:
131:            case 'integer':
132:                return (int) $var;
133:
134:            case 'double':
135:            case 'float':
136:                return (float) $var;
137:
138:            case 'string':
139:                $ascii = '';
140:                $strlen_var = strlen($var);
141:
142:                for ($c = 0; $c < $strlen_var; ++$c) {
143:
144:                    $ord_var_c = ord($var{$c});
145:
146:                    switch (true) {
147:                        case $ord_var_c == 0x08:
148:                            $ascii .= '\b';
149:                            break;
150:                        case $ord_var_c == 0x09:
151:                            $ascii .= '\t';
152:                            break;
153:                        case $ord_var_c == 0x0A:
154:                            $ascii .= '\n';
155:                            break;
156:                        case $ord_var_c == 0x0C:
157:                            $ascii .= '\f';
158:                            break;
159:                        case $ord_var_c == 0x0D:
160:                            $ascii .= '\r';
161:                            break;
162:
163:                        case $ord_var_c == 0x22:
164:                        case $ord_var_c == 0x2F:
165:                        case $ord_var_c == 0x5C:
166:                            $ascii .= '\\'.$var{$c};
167:                            break;
168:
169:                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
170:                            $ascii .= $var{$c};
171:                            break;
172:
173:                        case (($ord_var_c & 0xE0) == 0xC0):
174:                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
175:                            $c += 1;
176:                            $utf16 = self::utf82utf16($char);
177:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
178:                            break;
179:
180:                        case (($ord_var_c & 0xF0) == 0xE0):
181:                            $char = pack('C*', $ord_var_c,
182:                                         ord($var{$c + 1}),
183:                                         ord($var{$c + 2}));
184:                            $c += 2;
185:                            $utf16 = self::utf82utf16($char);
186:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
187:                            break;
188:
189:                        case (($ord_var_c & 0xF8) == 0xF0):
190:                            $char = pack('C*', $ord_var_c,
191:                                         ord($var{$c + 1}),
192:                                         ord($var{$c + 2}),
193:                                         ord($var{$c + 3}));
194:                            $c += 3;
195:                            $utf16 = self::utf82utf16($char);
196:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
197:                            break;
198:
199:                        case (($ord_var_c & 0xFC) == 0xF8):
200:                            $char = pack('C*', $ord_var_c,
201:                                         ord($var{$c + 1}),
202:                                         ord($var{$c + 2}),
203:                                         ord($var{$c + 3}),
204:                                         ord($var{$c + 4}));
205:                            $c += 4;
206:                            $utf16 = self::utf82utf16($char);
207:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
208:                            break;
209:
210:                        case (($ord_var_c & 0xFE) == 0xFC):
211:                            $char = pack('C*', $ord_var_c,
212:                                         ord($var{$c + 1}),
213:                                         ord($var{$c + 2}),
214:                                         ord($var{$c + 3}),
215:                                         ord($var{$c + 4}),
216:                                         ord($var{$c + 5}));
217:                            $c += 5;
218:                            $utf16 = self::utf82utf16($char);
219:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
220:                            break;
221:                    }
222:                }
223:
224:                return '"'.$ascii.'"';
225:
226:            case 'array':
227:                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
228:                    $properties = array_map(array('Json', '_name_value'),
229:                                            array_keys($var),
230:                                            array_values($var));
231:
232:                    foreach ($properties as $property) {
233:                        if (self::_is_error($property)) {
234:                            return $property;
235:                        }
236:                    }
237:
238:                    return '{' . join(',', $properties) . '}';
239:                }
240:
241:                // treat it like a regular array
242:                $elements = array_map(array('Json', '_encode'), $var);
243:
244:                foreach ($elements as $element) {
245:                    if (self::_is_error($element)) {
246:                        return $element;
247:                    }
248:                }
249:
250:                return '[' . join(',', $elements) . ']';
251:
252:            case 'object':
253:                $vars = get_object_vars($var);
254:
255:                $properties = array_map(array('Json', '_name_value'),
256:                                        array_keys($vars),
257:                                        array_values($vars));
258:
259:                foreach ($properties as $property) {
260:                    if (self::_is_error($property)) {
261:                        return $property;
262:                    }
263:                }
264:
265:                return '{' . join(',', $properties) . '}';
266:
267:            default:
268:                return false;
269:        }
270:    }
warning _encode array_map第0个参数,请使用闭包函数
代码
122:    public static function _encode($var)
123:    {
124:        switch (gettype($var)) {
125:            case 'boolean':
126:                return $var ? 'true' : 'false';
127:
128:            case 'NULL':
129:                return 'null';
130:
131:            case 'integer':
132:                return (int) $var;
133:
134:            case 'double':
135:            case 'float':
136:                return (float) $var;
137:
138:            case 'string':
139:                $ascii = '';
140:                $strlen_var = strlen($var);
141:
142:                for ($c = 0; $c < $strlen_var; ++$c) {
143:
144:                    $ord_var_c = ord($var{$c});
145:
146:                    switch (true) {
147:                        case $ord_var_c == 0x08:
148:                            $ascii .= '\b';
149:                            break;
150:                        case $ord_var_c == 0x09:
151:                            $ascii .= '\t';
152:                            break;
153:                        case $ord_var_c == 0x0A:
154:                            $ascii .= '\n';
155:                            break;
156:                        case $ord_var_c == 0x0C:
157:                            $ascii .= '\f';
158:                            break;
159:                        case $ord_var_c == 0x0D:
160:                            $ascii .= '\r';
161:                            break;
162:
163:                        case $ord_var_c == 0x22:
164:                        case $ord_var_c == 0x2F:
165:                        case $ord_var_c == 0x5C:
166:                            $ascii .= '\\'.$var{$c};
167:                            break;
168:
169:                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
170:                            $ascii .= $var{$c};
171:                            break;
172:
173:                        case (($ord_var_c & 0xE0) == 0xC0):
174:                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
175:                            $c += 1;
176:                            $utf16 = self::utf82utf16($char);
177:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
178:                            break;
179:
180:                        case (($ord_var_c & 0xF0) == 0xE0):
181:                            $char = pack('C*', $ord_var_c,
182:                                         ord($var{$c + 1}),
183:                                         ord($var{$c + 2}));
184:                            $c += 2;
185:                            $utf16 = self::utf82utf16($char);
186:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
187:                            break;
188:
189:                        case (($ord_var_c & 0xF8) == 0xF0):
190:                            $char = pack('C*', $ord_var_c,
191:                                         ord($var{$c + 1}),
192:                                         ord($var{$c + 2}),
193:                                         ord($var{$c + 3}));
194:                            $c += 3;
195:                            $utf16 = self::utf82utf16($char);
196:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
197:                            break;
198:
199:                        case (($ord_var_c & 0xFC) == 0xF8):
200:                            $char = pack('C*', $ord_var_c,
201:                                         ord($var{$c + 1}),
202:                                         ord($var{$c + 2}),
203:                                         ord($var{$c + 3}),
204:                                         ord($var{$c + 4}));
205:                            $c += 4;
206:                            $utf16 = self::utf82utf16($char);
207:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
208:                            break;
209:
210:                        case (($ord_var_c & 0xFE) == 0xFC):
211:                            $char = pack('C*', $ord_var_c,
212:                                         ord($var{$c + 1}),
213:                                         ord($var{$c + 2}),
214:                                         ord($var{$c + 3}),
215:                                         ord($var{$c + 4}),
216:                                         ord($var{$c + 5}));
217:                            $c += 5;
218:                            $utf16 = self::utf82utf16($char);
219:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
220:                            break;
221:                    }
222:                }
223:
224:                return '"'.$ascii.'"';
225:
226:            case 'array':
227:                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
228:                    $properties = array_map(array('Json', '_name_value'),
229:                                            array_keys($var),
230:                                            array_values($var));
231:
232:                    foreach ($properties as $property) {
233:                        if (self::_is_error($property)) {
234:                            return $property;
235:                        }
236:                    }
237:
238:                    return '{' . join(',', $properties) . '}';
239:                }
240:
241:                // treat it like a regular array
242:                $elements = array_map(array('Json', '_encode'), $var);
243:
244:                foreach ($elements as $element) {
245:                    if (self::_is_error($element)) {
246:                        return $element;
247:                    }
248:                }
249:
250:                return '[' . join(',', $elements) . ']';
251:
252:            case 'object':
253:                $vars = get_object_vars($var);
254:
255:                $properties = array_map(array('Json', '_name_value'),
256:                                        array_keys($vars),
257:                                        array_values($vars));
258:
259:                foreach ($properties as $property) {
260:                    if (self::_is_error($property)) {
261:                        return $property;
262:                    }
263:                }
264:
265:                return '{' . join(',', $properties) . '}';
266:
267:            default:
268:                return false;
269:        }
270:    }
warning _encode array_map第0个参数,请使用闭包函数
代码
122:    public static function _encode($var)
123:    {
124:        switch (gettype($var)) {
125:            case 'boolean':
126:                return $var ? 'true' : 'false';
127:
128:            case 'NULL':
129:                return 'null';
130:
131:            case 'integer':
132:                return (int) $var;
133:
134:            case 'double':
135:            case 'float':
136:                return (float) $var;
137:
138:            case 'string':
139:                $ascii = '';
140:                $strlen_var = strlen($var);
141:
142:                for ($c = 0; $c < $strlen_var; ++$c) {
143:
144:                    $ord_var_c = ord($var{$c});
145:
146:                    switch (true) {
147:                        case $ord_var_c == 0x08:
148:                            $ascii .= '\b';
149:                            break;
150:                        case $ord_var_c == 0x09:
151:                            $ascii .= '\t';
152:                            break;
153:                        case $ord_var_c == 0x0A:
154:                            $ascii .= '\n';
155:                            break;
156:                        case $ord_var_c == 0x0C:
157:                            $ascii .= '\f';
158:                            break;
159:                        case $ord_var_c == 0x0D:
160:                            $ascii .= '\r';
161:                            break;
162:
163:                        case $ord_var_c == 0x22:
164:                        case $ord_var_c == 0x2F:
165:                        case $ord_var_c == 0x5C:
166:                            $ascii .= '\\'.$var{$c};
167:                            break;
168:
169:                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
170:                            $ascii .= $var{$c};
171:                            break;
172:
173:                        case (($ord_var_c & 0xE0) == 0xC0):
174:                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
175:                            $c += 1;
176:                            $utf16 = self::utf82utf16($char);
177:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
178:                            break;
179:
180:                        case (($ord_var_c & 0xF0) == 0xE0):
181:                            $char = pack('C*', $ord_var_c,
182:                                         ord($var{$c + 1}),
183:                                         ord($var{$c + 2}));
184:                            $c += 2;
185:                            $utf16 = self::utf82utf16($char);
186:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
187:                            break;
188:
189:                        case (($ord_var_c & 0xF8) == 0xF0):
190:                            $char = pack('C*', $ord_var_c,
191:                                         ord($var{$c + 1}),
192:                                         ord($var{$c + 2}),
193:                                         ord($var{$c + 3}));
194:                            $c += 3;
195:                            $utf16 = self::utf82utf16($char);
196:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
197:                            break;
198:
199:                        case (($ord_var_c & 0xFC) == 0xF8):
200:                            $char = pack('C*', $ord_var_c,
201:                                         ord($var{$c + 1}),
202:                                         ord($var{$c + 2}),
203:                                         ord($var{$c + 3}),
204:                                         ord($var{$c + 4}));
205:                            $c += 4;
206:                            $utf16 = self::utf82utf16($char);
207:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
208:                            break;
209:
210:                        case (($ord_var_c & 0xFE) == 0xFC):
211:                            $char = pack('C*', $ord_var_c,
212:                                         ord($var{$c + 1}),
213:                                         ord($var{$c + 2}),
214:                                         ord($var{$c + 3}),
215:                                         ord($var{$c + 4}),
216:                                         ord($var{$c + 5}));
217:                            $c += 5;
218:                            $utf16 = self::utf82utf16($char);
219:                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
220:                            break;
221:                    }
222:                }
223:
224:                return '"'.$ascii.'"';
225:
226:            case 'array':
227:                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
228:                    $properties = array_map(array('Json', '_name_value'),
229:                                            array_keys($var),
230:                                            array_values($var));
231:
232:                    foreach ($properties as $property) {
233:                        if (self::_is_error($property)) {
234:                            return $property;
235:                        }
236:                    }
237:
238:                    return '{' . join(',', $properties) . '}';
239:                }
240:
241:                // treat it like a regular array
242:                $elements = array_map(array('Json', '_encode'), $var);
243:
244:                foreach ($elements as $element) {
245:                    if (self::_is_error($element)) {
246:                        return $element;
247:                    }
248:                }
249:
250:                return '[' . join(',', $elements) . ']';
251:
252:            case 'object':
253:                $vars = get_object_vars($var);
254:
255:                $properties = array_map(array('Json', '_name_value'),
256:                                        array_keys($vars),
257:                                        array_values($vars));
258:
259:                foreach ($properties as $property) {
260:                    if (self::_is_error($property)) {
261:                        return $property;
262:                    }
263:                }
264:
265:                return '{' . join(',', $properties) . '}';
266:
267:            default:
268:                return false;
269:        }
270:    }

./typecho/var/Upgrade.php

等级 函数 说明
danger v0_3r9_1_7 preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
30:    public static function v0_3r9_1_7($db, $options)
31:    {
32:        /** 转换评论 */
33:        $i = 1;
34:
35:        while (true) {
36:            $result = $db->query($db->select('coid', 'text')->from('table.comments')
37:            ->order('coid', Typecho_Db::SORT_ASC)->page($i, 100));
38:            $j = 0;
39:
40:            while ($row = $db->fetchRow($result)) {
41:                $text = nl2br($row['text']);
42:
43:                $db->query($db->update('table.comments')
44:                ->rows(array('text' => $text))
45:                ->where('coid = ?', $row['coid']));
46:
47:                $j ++;
48:                unset($text);
49:                unset($row);
50:            }
51:
52:            if ($j < 100) {
53:                break;
54:            }
55:
56:            $i ++;
57:            unset($result);
58:        }
59:
60:        /** 转换内容 */
61:        $i = 1;
62:
63:        while (true) {
64:            $result = $db->query($db->select('cid', 'text')->from('table.contents')
65:            ->order('cid', Typecho_Db::SORT_ASC)->page($i, 100));
66:            $j = 0;
67:
68:            while ($row = $db->fetchRow($result)) {
69:                $text = preg_replace(
70:                array("/\s*<p>/is", "/\s*<\/p>\s*/is", "/\s*<br\s*\/>\s*/is",
71:                "/\s*<(div|blockquote|pre|table|ol|ul)>/is", "/<\/(div|blockquote|pre|table|ol|ul)>\s*/is"),
72:                array('', "\n\n", "\n", "\n\n<\\1>", "</\\1>\n\n"),
73:                $row['text']);
74:
75:                $db->query($db->update('table.contents')
76:                ->rows(array('text' => $text))
77:                ->where('cid = ?', $row['cid']));
78:
79:                $j ++;
80:                unset($text);
81:                unset($row);
82:            }
83:
84:            if ($j < 100) {
85:                break;
86:            }
87:
88:            $i ++;
89:            unset($result);
90:        }
91:    }

./typecho/var/Helper.php

等级 函数 说明
warning widgetById 动态创建类对象,可能存在远程代码执行的隐患
代码
40:    public static function widgetById($table, $pkId)
41:    {
42:        $table = ucfirst($table);
43:        if (!in_array($table, array('Contents', 'Comments', 'Metas', 'Users'))) {
44:            return NULL;
45:        }
46:
47:        $keys = array(
48:            'Contents'  =>  'cid',
49:            'Comments'  =>  'coid',
50:            'Metas'     =>  'mid',
51:            'Users'     =>  'uid'
52:        );
53:
54:        $className = "Widget_Abstract_{$table}";
55:        $key = $keys[$table];
56:        $db = Typecho_Db::get();
57:        $widget = new $className;
58:        
59:        $db->fetchRow(
60:            $widget->select()->where("{$key} = ?", $pkId)->limit(1),
61:                array($widget, 'push'));
62:
63:        return $widget;
64:    }
danger removePlugin 文件包含操作存在动态变量或函数,可能有远程代码执行的隐患
代码
73:    public static function removePlugin($pluginName)
74:    {
75:        try {
76:            /** 获取插件入口 */
77:            list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, __TYPECHO_ROOT_DIR__ . '/' . __TYPECHO_PLUGIN_DIR__);
78:
79:            /** 获取已启用插件 */
80:            $plugins = Typecho_Plugin::export();
81:            $activatedPlugins = $plugins['activated'];
82:
83:            /** 载入插件 */
84:            require_once $pluginFileName;
85:
86:            /** 判断实例化是否成功 */
87:            if (!isset($activatedPlugins[$pluginName]) || !class_exists($className)
88:            || !method_exists($className, 'deactivate')) {
89:                throw new Typecho_Widget_Exception(_t('无法禁用插件'), 500);
90:            }
91:
92:            $result = call_user_func(array($className, 'deactivate'));
93:
94:        } catch (Exception $e) {
95:            //nothing to do
96:        }
97:
98:        $db = Typecho_Db::get();
99:
100:        try {
101:            Typecho_Plugin::deactivate($pluginName);
102:            $db->query($db->update('table.options')
103:            ->rows(array('value' => serialize(Typecho_Plugin::export())))
104:            ->where('name = ?', 'plugins'));
105:        } catch (Typecho_Plugin_Exception $e) {
106:            //nothing to do
107:        }
108:
109:        $db->query($db->delete('table.options')->where('name = ?', 'plugin:' . $pluginName));
110:    }
danger removePlugin call_user_func第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
73:    public static function removePlugin($pluginName)
74:    {
75:        try {
76:            /** 获取插件入口 */
77:            list($pluginFileName, $className) = Typecho_Plugin::portal($pluginName, __TYPECHO_ROOT_DIR__ . '/' . __TYPECHO_PLUGIN_DIR__);
78:
79:            /** 获取已启用插件 */
80:            $plugins = Typecho_Plugin::export();
81:            $activatedPlugins = $plugins['activated'];
82:
83:            /** 载入插件 */
84:            require_once $pluginFileName;
85:
86:            /** 判断实例化是否成功 */
87:            if (!isset($activatedPlugins[$pluginName]) || !class_exists($className)
88:            || !method_exists($className, 'deactivate')) {
89:                throw new Typecho_Widget_Exception(_t('无法禁用插件'), 500);
90:            }
91:
92:            $result = call_user_func(array($className, 'deactivate'));
93:
94:        } catch (Exception $e) {
95:            //nothing to do
96:        }
97:
98:        $db = Typecho_Db::get();
99:
100:        try {
101:            Typecho_Plugin::deactivate($pluginName);
102:            $db->query($db->update('table.options')
103:            ->rows(array('value' => serialize(Typecho_Plugin::export())))
104:            ->where('name = ?', 'plugins'));
105:        } catch (Typecho_Plugin_Exception $e) {
106:            //nothing to do
107:        }
108:
109:        $db->query($db->delete('table.options')->where('name = ?', 'plugin:' . $pluginName));
110:    }

./typecho/var/IXR/Server.php

等级 函数 说明
danger call 动态调用方法,可能存在远程代码执行的隐患
代码
75:    private function call($methodname, $args)
76:    {
77:        // hook
78:        if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.beforeCall')) {
79:            $this->call('hook.beforeCall', array($methodname));
80:        }
81:        
82:        if (!$this->hasMethod($methodname)) {
83:            return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
84:        }
85:        $method = $this->callbacks[$methodname];
86:
87:        // Are we dealing with a function or a method?
88:        if (is_string($method) && substr($method, 0, 5) == 'this:') {
89:            // It's a class method - check it exists
90:            $method = substr($method, 5);
91:            if (!method_exists($this, $method)) {
92:                return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
93:            }
94:            // Call the method
95:            $result = $this->$method($args);
96:        } else {
97:            if (is_array($method)) {
98:                list($object, $func) = $method;
99:                if (!is_callable($method)) {
100:                    return new IXR_Error(-32601, 'server error. requested class method "'.$object . '.' . $func.'" does not exist.');
101:                }
102:                
103:                $result = call_user_func_array(array($object, $func), $args);
104:            } elseif (!function_exists($method)) {
105:                // It's a function - does it exist?
106:                return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
107:            } else {
108:                // Call the function
109:                $result = $method($args);
110:            }
111:        }
112:        
113:        // hook
114:        if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.afterCall')) {
115:            $this->call('hook.afterCall', array($methodname));
116:        }
117:        
118:        return $result;
119:    }
danger call call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
75:    private function call($methodname, $args)
76:    {
77:        // hook
78:        if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.beforeCall')) {
79:            $this->call('hook.beforeCall', array($methodname));
80:        }
81:        
82:        if (!$this->hasMethod($methodname)) {
83:            return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
84:        }
85:        $method = $this->callbacks[$methodname];
86:
87:        // Are we dealing with a function or a method?
88:        if (is_string($method) && substr($method, 0, 5) == 'this:') {
89:            // It's a class method - check it exists
90:            $method = substr($method, 5);
91:            if (!method_exists($this, $method)) {
92:                return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
93:            }
94:            // Call the method
95:            $result = $this->$method($args);
96:        } else {
97:            if (is_array($method)) {
98:                list($object, $func) = $method;
99:                if (!is_callable($method)) {
100:                    return new IXR_Error(-32601, 'server error. requested class method "'.$object . '.' . $func.'" does not exist.');
101:                }
102:                
103:                $result = call_user_func_array(array($object, $func), $args);
104:            } elseif (!function_exists($method)) {
105:                // It's a function - does it exist?
106:                return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
107:            } else {
108:                // Call the function
109:                $result = $method($args);
110:            }
111:        }
112:        
113:        // hook
114:        if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.afterCall')) {
115:            $this->call('hook.afterCall', array($methodname));
116:        }
117:        
118:        return $result;
119:    }
danger call 动态调用函数,可能存在远程代码执行的隐患
代码
75:    private function call($methodname, $args)
76:    {
77:        // hook
78:        if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.beforeCall')) {
79:            $this->call('hook.beforeCall', array($methodname));
80:        }
81:        
82:        if (!$this->hasMethod($methodname)) {
83:            return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
84:        }
85:        $method = $this->callbacks[$methodname];
86:
87:        // Are we dealing with a function or a method?
88:        if (is_string($method) && substr($method, 0, 5) == 'this:') {
89:            // It's a class method - check it exists
90:            $method = substr($method, 5);
91:            if (!method_exists($this, $method)) {
92:                return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
93:            }
94:            // Call the method
95:            $result = $this->$method($args);
96:        } else {
97:            if (is_array($method)) {
98:                list($object, $func) = $method;
99:                if (!is_callable($method)) {
100:                    return new IXR_Error(-32601, 'server error. requested class method "'.$object . '.' . $func.'" does not exist.');
101:                }
102:                
103:                $result = call_user_func_array(array($object, $func), $args);
104:            } elseif (!function_exists($method)) {
105:                // It's a function - does it exist?
106:                return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
107:            } else {
108:                // Call the function
109:                $result = $method($args);
110:            }
111:        }
112:        
113:        // hook
114:        if (0 !== strpos($methodname, 'hook.') && $this->hasMethod('hook.afterCall')) {
115:            $this->call('hook.afterCall', array($methodname));
116:        }
117:        
118:        return $result;
119:    }

./typecho/var/IXR/Message.php

等级 函数 说明
danger parse preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
35:    function parse() {
36:        // first remove the XML declaration
37:        $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
38:        if (trim($this->message) == '') {
39:            return false;
40:        }
41:        $this->_parser = xml_parser_create();
42:        // Set XML parser to take the case of tags in to account
43:        xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
44:        // Set XML parser callback functions
45:        xml_set_object($this->_parser, $this);
46:        xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
47:        xml_set_character_data_handler($this->_parser, 'cdata');
48:        if (!xml_parse($this->_parser, $this->message)) {
49:            /* die(sprintf('XML error: %s at line %d',
50:                xml_error_string(xml_get_error_code($this->_parser)),
51:                xml_get_current_line_number($this->_parser))); */
52:            return false;
53:        }
54:        xml_parser_free($this->_parser);
55:        // Grab the error messages, if any
56:        if ($this->messageType == 'fault') {
57:            $this->faultCode = $this->params[0]['faultCode'];
58:            $this->faultString = $this->params[0]['faultString'];
59:        }
60:        return true;
61:    }

./typecho/var/IXR/Client.php

等级 函数 说明
danger __call call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
222:    public function __call($method, $args)
223:    {
224:        array_unshift($args, $this->prefix . $method);
225:        $return = call_user_func_array(array($this, '__rpcCall'), $args);
226:
227:        if ($return) {
228:            return $this->__getResponse();
229:        } else {
230:            require_once 'IXR/Exception.php';
231:            throw new IXR_Exception($this->__getErrorMessage(), $this->__getErrorCode());
232:        }
233:    }

./typecho/var/HyperDown.php

等级 函数 说明
danger parse 动态调用方法,可能存在远程代码执行的隐患
代码
185:    private function parse($text, $inline = false)
186:    {
187:        $blocks = $this->parseBlock($text, $lines);
188:        $html = '';
189:
190:        foreach ($blocks as $block) {
191:            list ($type, $start, $end, $value) = $block;
192:            $extract = array_slice($lines, $start, $end - $start + 1);
193:            $method = 'parse' . ucfirst($type);
194:
195:            $extract = $this->call('before' . ucfirst($method), $extract, $value);
196:            $result = $this->{$method}($extract, $value);
197:            $result = $this->call('after' . ucfirst($method), $result, $value);
198:
199:            $html .= $result;
200:        }
201:
202:        // inline mode for single normal block
203:        if ($inline && count($blocks) == 1 && $blocks[0][0] == 'normal') {
204:            // remove p tag
205:            $html = preg_replace("/^\s*<p>(.*)<\/p>\s*$/", "\\1", $html);
206:        }
207:
208:        return $html;
209:    }
danger call call_user_func_array第0个参数包含动态变量或函数,可能有远程代码执行的隐患
代码
236:    public function call($type, $value)
237:    {
238:        if (empty($this->_hooks[$type])) {
239:            return $value;
240:        }
241:
242:        $args = func_get_args();
243:        $args = array_slice($args, 1);
244:
245:        foreach ($this->_hooks[$type] as $callback) {
246:            $value = call_user_func_array($callback, $args);
247:            $args[0] = $value;
248:        }
249:
250:        return $value;
251:    }
danger parseCode preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
875:    private function parseCode(array $lines, array $parts)
876:    {
877:        list ($blank, $lang) = $parts;
878:        $lang = trim($lang);
879:        $count = strlen($blank);
880:
881:        if (!preg_match("/^[_a-z0-9-\+\#\:\.]+$/i", $lang)) {
882:            $lang = NULL;
883:        } else {
884:            $parts = explode(':', $lang);
885:            if (count($parts) > 1) {
886:                list ($lang, $rel) = $parts;
887:                $lang = trim($lang);
888:                $rel = trim($rel);
889:            }
890:        }
891:
892:        $lines = array_map(function ($line) use ($count) {
893:            return preg_replace("/^[ ]{{$count}}/", '', $line);
894:        }, array_slice($lines, 1, -1));
895:        $str = implode("\n", $lines);
896:
897:        return preg_match("/^\s*$/", $str) ? '' :
898:            '<pre><code' . (!empty($lang) ? " class=\"{$lang}\"" : '')
899:            . (!empty($rel) ? " rel=\"{$rel}\"" : '') . '>'
900:            . htmlspecialchars($str) . '</code></pre>';
901:    }
danger parseList preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
988:    private function parseList(array $lines)
989:    {
990:        $html = '';
991:        $minSpace = 99999;
992:        $rows = array();
993:
994:        // count levels
995:        foreach ($lines as $key => $line) {
996:            if (preg_match("/^(\s*)((?:[0-9a-z]+\.?)|\-|\+|\*)(\s+)(.*)$/", $line, $matches)) {
997:                $space = strlen($matches[1]);
998:                $type = false !== strpos('+-*', $matches[2]) ? 'ul' : 'ol';
999:                $minSpace = min($space, $minSpace);
1000:
1001:                $rows[] = array($space, $type, $line, $matches[4]);
1002:            } else {
1003:                $rows[] = $line;
1004:            }
1005:        }
1006:
1007:        $found = false;
1008:        $secondMinSpace = 99999;
1009:        foreach ($rows as $row) {
1010:            if (is_array($row) && $row[0] != $minSpace) {
1011:                $secondMinSpace = min($secondMinSpace, $row[0]);
1012:                $found = true;
1013:            }
1014:        }
1015:        $secondMinSpace = $found ? $secondMinSpace : $minSpace;
1016:
1017:        $lastType = '';
1018:        $leftLines = array();
1019:
1020:        foreach ($rows as $row) {
1021:            if (is_array($row)) {
1022:                list ($space, $type, $line, $text) = $row;
1023:
1024:                if ($space != $minSpace) {
1025:                    $leftLines[] = preg_replace("/^\s{" . $secondMinSpace . "}/", '', $line);
1026:                } else {
1027:                    if (!empty($leftLines)) {
1028:                        $html .= "<li>" . $this->parse(implode("\n", $leftLines), true) . "</li>";
1029:                    }
1030:
1031:                    if ($lastType != $type) {
1032:                        if (!empty($lastType)) {
1033:                            $html .= "</{$lastType}>";
1034:                        }
1035:
1036:                        $html .= "<{$type}>";
1037:                    }
1038:
1039:                    $leftLines = array($text);
1040:                    $lastType = $type;
1041:                }
1042:            } else {
1043:                $leftLines[] = preg_replace("/^\s{" . $secondMinSpace . "}/", '', $row);
1044:            }
1045:        }
1046:
1047:        if (!empty($leftLines)) {
1048:            $html .= "<li>" . $this->parse(implode("\n", $leftLines), true) . "</li></{$lastType}>";
1049:        }
1050:
1051:        return $html;
1052:    }
danger parseList preg_replace第一个参数不是静态字符串,可能存在远程代码执行的隐患
代码
988:    private function parseList(array $lines)
989:    {
990:        $html = '';
991:        $minSpace = 99999;
992:        $rows = array();
993:
994:        // count levels
995:        foreach ($lines as $key => $line) {
996:            if (preg_match("/^(\s*)((?:[0-9a-z]+\.?)|\-|\+|\*)(\s+)(.*)$/", $line, $matches)) {
997:                $space = strlen($matches[1]);
998:                $type = false !== strpos('+-*', $matches[2]) ? 'ul' : 'ol';
999:                $minSpace = min($space, $minSpace);
1000:
1001:                $rows[] = array($space, $type, $line, $matches[4]);
1002:            } else {
1003:                $rows[] = $line;
1004:            }
1005:        }
1006:
1007:        $found = false;
1008:        $secondMinSpace = 99999;
1009:        foreach ($rows as $row) {
1010:            if (is_array($row) && $row[0] != $minSpace) {
1011:                $secondMinSpace = min($secondMinSpace, $row[0]);
1012:                $found = true;
1013:            }
1014:        }
1015:        $secondMinSpace = $found ? $secondMinSpace : $minSpace;
1016:
1017:        $lastType = '';
1018:        $leftLines = array();
1019:
1020:        foreach ($rows as $row) {
1021:            if (is_array($row)) {
1022:                list ($space, $type, $line, $text) = $row;
1023:
1024:                if ($space != $minSpace) {
1025:                    $leftLines[] = preg_replace("/^\s{" . $secondMinSpace . "}/", '', $line);
1026:                } else {
1027:                    if (!empty($leftLines)) {
1028:                        $html .= "<li>" . $this->parse(implode("\n", $leftLines), true) . "</li>";
1029:                    }
1030:
1031:                    if ($lastType != $type) {
1032:                        if (!empty($lastType)) {
1033:                            $html .= "</{$lastType}>";
1034:                        }
1035:
1036:                        $html .= "<{$type}>";
1037:                    }
1038:
1039:                    $leftLines = array($text);
1040:                    $lastType = $type;
1041:                }
1042:            } else {
1043:                $leftLines[] = preg_replace("/^\s{" . $secondMinSpace . "}/", '', $row);
1044:            }
1045:        }
1046:
1047:        if (!empty($leftLines)) {
1048:            $html .= "<li>" . $this->parse(implode("\n", $leftLines), true) . "</li></{$lastType}>";
1049:        }
1050:
1051:        return $html;
1052:    }