├── public ├── mobile.js ├── css │ ├── mobile.css │ ├── dot.png │ ├── arrow.png │ ├── icons.gif │ ├── logo.png │ ├── noise.png │ ├── avatar.png │ ├── btn_page.png │ ├── bubble.png │ ├── circle.png │ ├── cover_bg.png │ ├── dialog.png │ ├── img_bg_2.png │ ├── loader.gif │ ├── pattern.png │ ├── reg_bg.png │ ├── reload.png │ ├── sprite.png │ ├── sprites.png │ ├── account_bg.png │ ├── direction.png │ ├── footer_bg.gif │ ├── msg_close.png │ ├── top_arrow.png │ ├── attach_shadow.png │ ├── blue_circle.png │ ├── gb_tip_layer.png │ ├── loading_msg.gif │ ├── msg_loading.gif │ ├── comment_shaodow.png │ ├── childreply_arrow.png │ ├── gb_tip_layer_ie6.png │ ├── eclipse.css │ ├── m.css │ └── icon.css ├── fonts │ ├── icomoon.eot │ ├── icomoon.ttf │ ├── icomoon.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── jquery.jscrollbar-2.0.0.min.js ├── jquery.caret.min.js ├── zepto.timeago.js ├── cropbox.js ├── jquery.timeago.js └── jquery.devbridge-autocomplete.min.js ├── application ├── securimage │ ├── database │ │ ├── index.html │ │ ├── .htaccess │ │ └── securimage.sq3 │ ├── audio │ │ └── .htaccess │ ├── AHGBold.ttf │ ├── backgrounds │ │ ├── bg3.jpg │ │ ├── bg4.jpg │ │ ├── bg5.jpg │ │ └── bg6.png │ ├── images │ │ ├── refresh.png │ │ └── audio_icon.png │ ├── securimage_play.swf │ ├── README.FONT.txt │ ├── LICENSE.txt │ ├── securimage_play.php │ ├── securimage_show.php │ ├── example_form.ajax.php │ ├── README.txt │ └── example_form.php ├── views │ └── default │ │ ├── index.php │ │ ├── page_btn.php │ │ ├── user_collect.php │ │ ├── user_thread.php │ │ ├── list.php │ │ ├── pager.php │ │ ├── user_info.php │ │ ├── user_avatar.php │ │ ├── user_reply.php │ │ ├── user_top.php │ │ ├── err404.php │ │ ├── header.php │ │ ├── user_setting.php │ │ └── user_notifications.php ├── models │ ├── profileModel.php │ ├── mainModel.php │ ├── accountModel.php │ └── userModel.php ├── thumb │ ├── ThumbLib.inc.php │ ├── PhpThumb.inc.php │ └── ThumbBase.inc.php └── controllers │ ├── mainController.php │ ├── accountController.php │ └── userController.php ├── .htaccess ├── system ├── model.php ├── view.php ├── config.php └── controller.php ├── index.php ├── monster.sql └── README.md /public/mobile.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/css/mobile.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /application/securimage/database/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /application/securimage/audio/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all 2 | -------------------------------------------------------------------------------- /application/securimage/database/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all 2 | -------------------------------------------------------------------------------- /public/css/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/dot.png -------------------------------------------------------------------------------- /public/css/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/arrow.png -------------------------------------------------------------------------------- /public/css/icons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/icons.gif -------------------------------------------------------------------------------- /public/css/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/logo.png -------------------------------------------------------------------------------- /public/css/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/noise.png -------------------------------------------------------------------------------- /public/css/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/avatar.png -------------------------------------------------------------------------------- /public/css/btn_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/btn_page.png -------------------------------------------------------------------------------- /public/css/bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/bubble.png -------------------------------------------------------------------------------- /public/css/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/circle.png -------------------------------------------------------------------------------- /public/css/cover_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/cover_bg.png -------------------------------------------------------------------------------- /public/css/dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/dialog.png -------------------------------------------------------------------------------- /public/css/img_bg_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/img_bg_2.png -------------------------------------------------------------------------------- /public/css/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/loader.gif -------------------------------------------------------------------------------- /public/css/pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/pattern.png -------------------------------------------------------------------------------- /public/css/reg_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/reg_bg.png -------------------------------------------------------------------------------- /public/css/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/reload.png -------------------------------------------------------------------------------- /public/css/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/sprite.png -------------------------------------------------------------------------------- /public/css/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/sprites.png -------------------------------------------------------------------------------- /public/css/account_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/account_bg.png -------------------------------------------------------------------------------- /public/css/direction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/direction.png -------------------------------------------------------------------------------- /public/css/footer_bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/footer_bg.gif -------------------------------------------------------------------------------- /public/css/msg_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/msg_close.png -------------------------------------------------------------------------------- /public/css/top_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/top_arrow.png -------------------------------------------------------------------------------- /public/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/fonts/icomoon.eot -------------------------------------------------------------------------------- /public/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/fonts/icomoon.ttf -------------------------------------------------------------------------------- /public/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/fonts/icomoon.woff -------------------------------------------------------------------------------- /public/css/attach_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/attach_shadow.png -------------------------------------------------------------------------------- /public/css/blue_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/blue_circle.png -------------------------------------------------------------------------------- /public/css/gb_tip_layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/gb_tip_layer.png -------------------------------------------------------------------------------- /public/css/loading_msg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/loading_msg.gif -------------------------------------------------------------------------------- /public/css/msg_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/msg_loading.gif -------------------------------------------------------------------------------- /public/css/comment_shaodow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/comment_shaodow.png -------------------------------------------------------------------------------- /public/css/childreply_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/childreply_arrow.png -------------------------------------------------------------------------------- /public/css/gb_tip_layer_ie6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/css/gb_tip_layer_ie6.png -------------------------------------------------------------------------------- /application/securimage/AHGBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/AHGBold.ttf -------------------------------------------------------------------------------- /application/securimage/backgrounds/bg3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/backgrounds/bg3.jpg -------------------------------------------------------------------------------- /application/securimage/backgrounds/bg4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/backgrounds/bg4.jpg -------------------------------------------------------------------------------- /application/securimage/backgrounds/bg5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/backgrounds/bg5.jpg -------------------------------------------------------------------------------- /application/securimage/backgrounds/bg6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/backgrounds/bg6.png -------------------------------------------------------------------------------- /application/securimage/images/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/images/refresh.png -------------------------------------------------------------------------------- /application/securimage/securimage_play.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/securimage_play.swf -------------------------------------------------------------------------------- /application/securimage/images/audio_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/images/audio_icon.png -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /application/securimage/database/securimage.sq3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/application/securimage/database/securimage.sq3 -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinebay/monster/HEAD/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteCond %{REQUEST_FILENAME} !-f 4 | RewriteCond %{REQUEST_FILENAME} !-d 5 | RewriteRule . index.php [L] 6 | 7 | 8 | # Prevent file browsing 9 | Options -Indexes 10 | -------------------------------------------------------------------------------- /application/views/default/index.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 |
7 | -------------------------------------------------------------------------------- /application/models/profileModel.php: -------------------------------------------------------------------------------- 1 | thread_prefix=$this->model('thread')->prefix; 7 | } 8 | } 9 | 10 | ?> 11 | -------------------------------------------------------------------------------- /application/securimage/README.FONT.txt: -------------------------------------------------------------------------------- 1 | AHGBold.ttf is used by Securimage under the following license: 2 | 3 | Alte Haas Grotesk is a typeface that look like an helvetica printed in an old Muller-Brockmann Book. 4 | 5 | These fonts are freeware and can be distributed as long as they are 6 | together with this text file. 7 | 8 | I would appreciate very much to see what you have done with it anyway. 9 | 10 | yann le coroller 11 | www.yannlecoroller.com 12 | yann@lecoroller.com -------------------------------------------------------------------------------- /application/views/default/page_btn.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /application/views/default/user_collect.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 8 |
9 |
10 | 对方关闭了查看收藏列表权限 11 |
12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /application/views/default/user_thread.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 8 |
9 |
10 | 对方关闭了查看帖子列表权限 11 |
12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /system/model.php: -------------------------------------------------------------------------------- 1 | config=$config; 11 | require_once(APP_DIR.'db'.DIRECTORY_SEPARATOR.'db.class.php'); 12 | include_once(APP_DIR.'db'.DIRECTORY_SEPARATOR.'SSDB.php'); 13 | $this->mysql=new db(); 14 | $this->ssdb = new SimpleSSDB('127.0.0.1',8888); 15 | } 16 | public function model($name){ 17 | $model_name=$name.'Model'; 18 | if($model_name!=get_class($this)){ 19 | require_once(APP_DIR .'models'.DIRECTORY_SEPARATOR. strtolower($name) .'Model.php'); 20 | $model = new $model_name; 21 | }else{ 22 | $model = $this; 23 | } 24 | return $model; 25 | } 26 | } 27 | ?> 28 | -------------------------------------------------------------------------------- /public/css/eclipse.css: -------------------------------------------------------------------------------- 1 | .cm-s-eclipse span.cm-meta { color: #FF1717; } 2 | .cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } 3 | .cm-s-eclipse span.cm-atom { color: #219; } 4 | .cm-s-eclipse span.cm-number { color: #164; } 5 | .cm-s-eclipse span.cm-def { color: #00f; } 6 | .cm-s-eclipse span.cm-variable { color: black; } 7 | .cm-s-eclipse span.cm-variable-2 { color: #0000C0; } 8 | .cm-s-eclipse span.cm-variable-3 { color: #0000C0; } 9 | .cm-s-eclipse span.cm-property { color: black; } 10 | .cm-s-eclipse span.cm-operator { color: black; } 11 | .cm-s-eclipse span.cm-comment { color: #3F7F5F; } 12 | .cm-s-eclipse span.cm-string { color: #2A00FF; } 13 | .cm-s-eclipse span.cm-string-2 { color: #f50; } 14 | .cm-s-eclipse span.cm-qualifier { color: #555; } 15 | .cm-s-eclipse span.cm-builtin { color: #30a; } 16 | .cm-s-eclipse span.cm-bracket { color: #cc7; } 17 | .cm-s-eclipse span.cm-tag { color: #170; } 18 | .cm-s-eclipse span.cm-attribute { color: #00c; } 19 | .cm-s-eclipse span.cm-link { color: #219; } 20 | .cm-s-eclipse span.cm-error { color: #f00; } 21 | 22 | .cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; } 23 | .cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } 24 | -------------------------------------------------------------------------------- /application/securimage/LICENSE.txt: -------------------------------------------------------------------------------- 1 | COPYRIGHT: 2 | Copyright (c) 2011 Drew Phillips 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | - Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | - Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | 26 | -------------------------------------------------------------------------------- /application/models/mainModel.php: -------------------------------------------------------------------------------- 1 | thread_prefix=$this->model('thread')->prefix; 7 | } 8 | /* 9 | * @param int $last_id 10 | * @param int $direction 11 | * @param char $type(hot_thread,thread,user_collect) 12 | */ 13 | public function getThreads($type,$last_id,$direction){ 14 | if($direction==1){ 15 | $thread_id_list=$this->ssdb->zrscan($type,$this->thread_prefix.$last_id,'','',$this->config['thread_per_page']+1); 16 | }else{ 17 | $thread_id_list=$this->ssdb->zscan($type,$this->thread_prefix.$last_id,'','',$this->config['thread_per_page']+1); 18 | } 19 | $thread_id_list=array_keys($thread_id_list); 20 | $thread_info_list=$this->model('thread')->getThreadInfoById($thread_id_list,false); 21 | $threads=array(); 22 | if(count($thread_id_list)>0){ 23 | $threads=array_combine($thread_id_list,$thread_info_list); 24 | } 25 | foreach($threads as $k=>$v){ 26 | if($v['uid']==''){ 27 | unset($threads[$k]); 28 | } 29 | } 30 | return $threads; 31 | } 32 | public function getSiteCounter(){ 33 | return array( 34 | 'thread_count'=>$this->ssdb->get('thread_count'), 35 | 'user_count'=>$this->ssdb->get('user_count') 36 | ); 37 | } 38 | } 39 | 40 | ?> 41 | -------------------------------------------------------------------------------- /application/models/accountModel.php: -------------------------------------------------------------------------------- 1 | mysql->table('user')->where(array('email'=>$email,'pwd'=>pwd_encode($pwd)))->field('uid,username')->find(); 13 | } 14 | public function userIsExist($attrname,$attr){ 15 | $count=$this->mysql->table('user')->where(array($attrname=>$attr))->count(); 16 | return $count>0?true:false; 17 | } 18 | public function addUser($username,$email,$pwd){ 19 | $uid=$this->mysql->table('user')->data(array('username'=>$username,'email'=>$email,'pwd'=>pwd_encode($pwd)))->insert(); 20 | if($uid>0){ 21 | $this->ssdb->multi_hset($this->model('user')->prefix.$uid, 22 | array( 23 | 'uid'=>$uid, 24 | 'username'=>$username, 25 | 'email'=> $email, 26 | 'pwd'=> pwd_encode($pwd), 27 | 'reg_ip'=> getIp(), 28 | 'last_reply_time'=>0, 29 | 'last_thread_add_time'=>0, 30 | 'last_msg_send_time'=>0, 31 | 'new_notice'=>0, 32 | 'new_msg'=>'', 33 | 'small_avatar'=>'', 34 | 'big_avatar'=>'', 35 | 'collect_num'=>0, 36 | 'reply_num'=>0, 37 | 'thread_num'=>0, 38 | 'ctime'=>time() 39 | )); 40 | $this->ssdb->set('user_count',$uid); 41 | return $uid; 42 | }else{ 43 | return false; 44 | } 45 | } 46 | } 47 | 48 | ?> 49 | -------------------------------------------------------------------------------- /application/views/default/list.php: -------------------------------------------------------------------------------- 1 | 0):foreach($thread_list as $k=>$v):?> 2 |
3 |
4 | 5 | 6 | 7 | 8 |

9 |
10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 | 浏览() 18 | 回复() 19 | 投票() 20 | 收藏() 21 | uid==1): ?>删除 22 | 发表于 23 |
24 |
25 |
26 | 27 |
28 |
29 | 暂无相关帖子 30 |
31 | -------------------------------------------------------------------------------- /application/views/default/pager.php: -------------------------------------------------------------------------------- 1 | 0)||($direction==0&&$prev_has_more)){ 14 | reset($arr); 15 | $prev=get_number(key($arr)); 16 | } 17 | if(($direction==1&&$next_has_more)||($direction==0&&$last_id>0)){ 18 | end($arr); 19 | $next=get_number(key($arr)); 20 | } 21 | return array( 22 | 'arr'=>$arr, 23 | 'prev'=>$prev, 24 | 'next'=>$next 25 | ); 26 | } 27 | 28 | /*if($direction==0){ 29 | $prev_has_more=count(array_keys($reply))==($this->config['reply_per_page']+1)?true:false; 30 | $reply=array_slice($reply,0,$this->config['reply_per_page']); 31 | $reply=array_reverse($reply,true); 32 | }else{ 33 | $next_has_more=count(array_keys($reply))==($this->config['reply_per_page']+1)?true:false; 34 | $reply=array_slice($reply,0,$this->config['reply_per_page']); 35 | } 36 | $prev=''; 37 | $next=''; 38 | if(($direction==1&&$last_id>0)||($direction==0&&$prev_has_more)){ 39 | reset($reply); 40 | $prev=url('thread/view',array('category_name'=>urldecode($category_name),'thread_title'=>urldecode($thread_title),'thread_id'=>$thread_id,'last_id'=>str_replace('r','',key($reply)),'direction'=>0)); 41 | } 42 | if(($direction==1&&$next_has_more)||($direction==0&&$last_id>0)){ 43 | end($reply); 44 | $next=url('thread/view',array('category_name'=>urldecode($category_name),'thread_title'=>urldecode($thread_title),'thread_id'=>$thread_id,'last_id'=>str_replace('r','',key($reply)),'direction'=>1)); 45 | }*/ -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | $handler_name) { 31 | if (preg_match(route($pattern), $url_clean, $matches)) { 32 | $discovered_handler = $handler_name; 33 | $regex_matches = $matches; 34 | break; 35 | } 36 | } 37 | $handler=explode('/',$discovered_handler); 38 | } 39 | $handler_instance = null; 40 | $controller=$handler[0].'Controller'; 41 | $path = APP_DIR . 'controllers'.DIRECTORY_SEPARATOR. $controller .'.php'; 42 | file_exists($path)?require_once($path):header("HTTP/1.1 404 Not Found").require_once(APP_DIR . 'views/default/err404.php'); 43 | $handler_instance=new $controller(); 44 | foreach($regex_matches as $k=>$v){ 45 | if(is_int($k)){ 46 | unset($regex_matches[$k]); 47 | } 48 | } 49 | method_exists($controller,$handler[1])&&call_user_func_array(array($handler_instance,$handler[1]), $regex_matches); 50 | ?> -------------------------------------------------------------------------------- /monster.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 4.2.2 3 | -- http://www.phpmyadmin.net 4 | -- 5 | -- Host: localhost 6 | -- Generation Time: 2016-04-20 22:06:49 7 | -- 服务器版本: 5.7.4-m14 8 | -- PHP Version: 5.5.12 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | SET time_zone = "+00:00"; 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8 */; 18 | 19 | -- 20 | -- Database: `monster` 21 | -- 22 | 23 | -- -------------------------------------------------------- 24 | 25 | -- 26 | -- 表的结构 `ms_thread` 27 | -- 28 | 29 | CREATE TABLE IF NOT EXISTS `ms_thread` ( 30 | `thread_id` int(10) unsigned NOT NULL, 31 | `thread_keywords` text NOT NULL 32 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 33 | 34 | -- -------------------------------------------------------- 35 | 36 | -- 37 | -- 表的结构 `ms_user` 38 | -- 39 | 40 | CREATE TABLE IF NOT EXISTS `ms_user` ( 41 | `uid` int(10) unsigned NOT NULL, 42 | `username` varchar(100) NOT NULL, 43 | `email` text NOT NULL, 44 | `pwd` text NOT NULL 45 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 46 | 47 | -- 48 | -- Indexes for dumped tables 49 | -- 50 | 51 | -- 52 | -- Indexes for table `ms_thread` 53 | -- 54 | ALTER TABLE `ms_thread` 55 | ADD PRIMARY KEY (`thread_id`), ADD FULLTEXT KEY `thread_keywords` (`thread_keywords`); 56 | 57 | -- 58 | -- Indexes for table `ms_user` 59 | -- 60 | ALTER TABLE `ms_user` 61 | ADD PRIMARY KEY (`uid`); 62 | 63 | -- 64 | -- AUTO_INCREMENT for dumped tables 65 | -- 66 | 67 | -- 68 | -- AUTO_INCREMENT for table `ms_thread` 69 | -- 70 | ALTER TABLE `ms_thread` 71 | MODIFY `thread_id` int(10) unsigned NOT NULL AUTO_INCREMENT; 72 | -- 73 | -- AUTO_INCREMENT for table `ms_user` 74 | -- 75 | ALTER TABLE `ms_user` 76 | MODIFY `uid` int(10) unsigned NOT NULL AUTO_INCREMENT; 77 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 78 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 79 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 80 | -------------------------------------------------------------------------------- /system/view.php: -------------------------------------------------------------------------------- 1 | config=$config; 10 | } 11 | 12 | public function set($var, $val) 13 | { 14 | $this->pageVars[$var] = $val; 15 | } 16 | 17 | public function render($template) 18 | { 19 | $tpl_cache=ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl'.DIRECTORY_SEPARATOR.$this->config['theme'].DIRECTORY_SEPARATOR.$template.'.php'; 20 | $tpl=APP_DIR.'views'.DIRECTORY_SEPARATOR . $this->config['theme'].DIRECTORY_SEPARATOR . strtolower($template).'.php'; 21 | if(!file_exists($tpl_cache)){ 22 | if(!is_dir(ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl'.DIRECTORY_SEPARATOR.$this->config['theme'])){ 23 | mkdir(ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl',0755); 24 | mkdir(ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl'.DIRECTORY_SEPARATOR.$this->config['theme'],0755); 25 | } 26 | copy($tpl,$tpl_cache); 27 | $match=true; 28 | while($match){ 29 | $tpl_content=file_get_contents($tpl_cache); 30 | preg_match_all('/(include|require|include_once|require_once)\((\"|\')(.*?)(\"|\')\)(\s*)\;/',$tpl_content,$matches); 31 | $pattern=array(); 32 | $replace=array(); 33 | if(count($matches[0])>0){ 34 | foreach($matches[0] as $k=>$v){ 35 | $pattern[]='/\<\?php(\s*)'.preg_quote($v).'(\s*)\?\>/'; 36 | $replace[]=file_get_contents(APP_DIR .'views'.DIRECTORY_SEPARATOR.$this->config['theme'].DIRECTORY_SEPARATOR.$matches[3][$k]); 37 | } 38 | $tpl_temp=preg_replace($pattern,$replace,$tpl_content); 39 | file_put_contents($tpl_cache,$tpl_temp); 40 | }else{ 41 | $match=false; 42 | } 43 | } 44 | } 45 | extract($this->pageVars); 46 | ob_start(); 47 | if(CACHE_ON){ 48 | include($tpl_cache); 49 | }else{ 50 | include($tpl); 51 | } 52 | echo ob_get_clean(); 53 | } 54 | 55 | } 56 | 57 | ?> -------------------------------------------------------------------------------- /application/views/default/user_info.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 |
个人介绍:
7 |
个人网址:
8 |
个人微博:
9 |
Dribbble:
10 |
GitHub:
11 |
Facebook:
12 |
Twitter:
13 | uid!=$user_info['uid']): ?> 14 |
共回复过我次数:
15 |
共赞过我次数:
16 | 17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /application/views/default/user_avatar.php: -------------------------------------------------------------------------------- 1 | 2 | 21 |
22 |
23 | 24 |
25 | 26 |
27 | 28 |
29 |
30 |
31 | 32 |
33 | 38 |
39 |
40 |


41 | 42 | 点击上传您的头像 43 | 44 | 45 |


46 |

支持的图片格式:jpeg jpg png. 图片大小<1MB

47 |
48 |
49 |
50 |
51 |
52 | -------------------------------------------------------------------------------- /application/securimage/securimage_play.php: -------------------------------------------------------------------------------- 1 | 5 | * File: securimage_play.php
6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or any later version.

11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details.

16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

20 | * 21 | * Any modifications to the library should be indicated clearly in the source code 22 | * to inform users that the changes are not a part of the original software.

23 | * 24 | * If you found this script useful, please take a quick moment to rate it.
25 | * http://www.hotscripts.com/rate/49400.html Thanks. 26 | * 27 | * @link http://www.phpcaptcha.org Securimage PHP CAPTCHA 28 | * @link http://www.phpcaptcha.org/latest.zip Download Latest Version 29 | * @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation 30 | * @copyright 2012 Drew Phillips 31 | * @author Drew Phillips 32 | * @version 3.5.2 (Feb 15, 2014) 33 | * @package Securimage 34 | * 35 | */ 36 | 37 | require_once dirname(__FILE__) . '/securimage.php'; 38 | 39 | // if using database, adjust these options as necessary and change $img = new Securimage(); to $img = new Securimage($options); 40 | // see test.mysql.php or test.sqlite.php for examples 41 | $options = array( 42 | 'use_database' => true, 43 | 'database_name' => '', 44 | 'database_user' => '', 45 | 'database_driver' => Securimage::SI_DRIVER_MYSQL 46 | ); 47 | 48 | $img = new Securimage(); 49 | 50 | // Other audio settings 51 | //$img->audio_use_sox = true; 52 | //$img->audio_use_noise = true; 53 | //$img->degrade_audio = false; 54 | //$img->sox_binary_path = 'sox'; 55 | 56 | // To use an alternate language, uncomment the following and download the files from phpcaptcha.org 57 | // $img->audio_path = $img->securimage_path . '/audio/es/'; 58 | 59 | // If you have more than one captcha on a page, one must use a custom namespace 60 | // $img->namespace = 'form2'; 61 | 62 | // set namespace if supplied to script via HTTP GET 63 | if (!empty($_GET['namespace'])) $img->setNamespace($_GET['namespace']); 64 | 65 | $img->outputAudioFile(); 66 | -------------------------------------------------------------------------------- /system/config.php: -------------------------------------------------------------------------------- 1 | '',//站点网址,如:http://www.abc.com 支持二级目录 7 | 'public'=>'',//站点静态文件目录 8 | 'shortname'=>'Monster',//站点名称简写 9 | 'db'=>array( 10 | 'db_host'=>'localhost', 11 | 'db_name'=>'monster',//MySQL数据库名称,默认为monster 12 | 'db_username'=>'',//MySQL数据库用户名 13 | 'db_password'=>'',//MySQL数据库密码 14 | 'db_prefix'=>'ms_',//MySQL数据表前缀,默认为ms_ 15 | 'db_port'=>3306, 16 | 'db_charset'=>'utf8' 17 | ), 18 | 'router'=>array(//站点全局URL路由配置,其中“!”代表字符串型变量,“#”代表整型变量 19 | '/'=>'main/index', 20 | '//<#last_id>-<#direction>'=>'main/threads', 21 | '/category/<#category_id>-<#last_id>-<#direction>'=>'main/category', 22 | '/<#thread_id>-<#last_id>-<#direction>'=>'thread/view', 23 | '/t/search/-<#last_id>-<#direction>'=>'thread/search', 24 | '/user/<#uid>'=>'user/index', 25 | '/user/<#uid>/thread-<#last_id>-<#direction>'=>'user/thread', 26 | '/user/<#uid>/collect-<#last_id>-<#direction>'=>'user/collect', 27 | '/user/<#uid>/reply-<#last_id>-<#direction>'=>'user/reply', 28 | '/profile'=>'profile/index', 29 | '/profile/avatar'=>'profile/avatar', 30 | '/profile/collect-<#last_id>-<#direction>'=>'profile/collect', 31 | '/profile/thread-<#last_id>-<#direction>'=>'profile/thread', 32 | '/profile/reply-<#last_id>-<#direction>'=>'profile/reply', 33 | '/profile/setting'=>'profile/setting', 34 | '/profile/notifications-<#last_id>-<#direction>'=>'profile/notifications', 35 | '/profile/msg'=>'profile/msg', 36 | ), 37 | 'tietuku_token'=>'',//贴图库Token 38 | 'cookie_prefix'=>'ms_',//站点cookie前缀 39 | 'key'=>'fhi28YHiut65hr2oy9hu4899283hIT812HU0gyt7ff546FO2SSDUih78Tgi',//站点cookie混淆码,可输入随机字符 40 | 'theme'=>'default',//站点模板文件夹名称,当自行添加新模板时,可在此填写新模板文件夹名称 41 | 'show_login_captcha'=>true,//是否显示登录验证码 42 | 'show_register_captcha'=>true,//是否显示注册验证码 43 | 'close_register'=>false,//是否关闭站点注册 44 | 'reply_live_time'=>60,//对指定帖子回复间隔时间,单位:秒 45 | 'global_reply_live_time'=>10,//对全局回复的间隔时间,单位:秒 46 | 'thread_add_interval_time'=>300,//全局发帖频率间隔时间,单位:秒 47 | 'thread_per_page'=>6,//每页显示帖子数 48 | 'reply_per_page'=>10,//每页显示回复数 49 | 'msg_record_queue'=>10,//用户在msg_record_queue次发送私信行为中,平均发送时间低于msg_send_interval_time(秒)则不能发送私信 50 | 'msg_send_interval_time'=>60,//用户在msg_record_queue次发送私信行为中,平均发送时间低于msg_send_interval_time(秒)则不能发送私信,单位:秒 51 | 'default_big_avatar'=>'http://i3.tietuku.cn/a1c072e7db9e3171.png',//默认大头像文件 52 | 'default_small_avatar'=>'http://i1.tietuku.cn/790079f4c958331f.png',//默认小头像文件 53 | 'category'=>array(//站点分类名称数组 54 | 1=>'猿类杂谈', 55 | 2=>'发现与创造', 56 | 3=>'vps及服务器', 57 | 4=>'招聘推广', 58 | 5=>'SSDB', 59 | 6=>'bug反馈' 60 | ) 61 | ); 62 | ?> -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## 技术层面 ## 6 | 从mockup构想到页面psd设计,再到HTML+css的编写,以及后端php mvc框架编写和数据逻辑的实现,此程序的前后端都由我一个人编写,因此代码上难免有疏忽之处,希望能予以指出。 7 | 8 | **前端:** 9 | 为设计一种美观和简洁的前端UI,前端摒弃了任何UI框架,只引用了jquery,纯手写了一个公共的global.js和base.css,系统图标采用了icomoon的web font,因此前端修改起来非常简单,同时前端引用的库有: 10 | 11 | - cropbox.js:用于头像上传时裁剪,[https://plugins.jquery.com/cropbox/][2] 12 | - jquery.devbridge-autocomplete.min.js,用于生成搜索候选下拉框[https://github.com/devbridge/jQuery-Autocomplete][3] 13 | - jquery.jscrollbar-2.0.0.min.js,私信页面时的滚动条替换[https://github.com/daiying-zhang/jquery.jscrollbar][4] 14 | - jquery.timeago.js,私信页面时间友好化显示,[http://timeago.yarp.com][5] 15 | - switchery.min.js,注册登录时的checkbox替换[http://abpetkov.github.io/switchery/][6] 16 | - tipsy,用于鼠标hover时的提示[http://onehackoranother.com/projects/jquery/tipsy/][12] 17 | 18 | **后端:** 19 | 架设一个常规的简单论坛,其实大家第一反应也就是MySQL中建立4个表,user表存储用户信息,thread表存储帖子信息,reply表存储回复信息,notification表存储用户通知信息,一个论坛后端数据库就做完了,配合php写点基础验证逻辑,加上个memcache缓存帖子、回复、用户等信息,一个最简单的论坛就架设成了。我这次便想尝试一次全新的数据架构:用NoSQL作为主存储去编写一个论坛,最终选中了SSDB作为全站的主存储,SSDB([http://ssdb.io/][7])简单的说就是一个存储在硬盘上的redis,由于其和redis有相同的使用协议,但内核基于Google的leveldb进行封装,支持十亿级别的数据存储,因而相对于redis这样的内存性数据库而言,其优势不言而喻。 20 | 21 | 使用SSDB的hset存储用户信息、帖子信息、回复信息,用kv存储一些较为简单的数据结构如通知信息以及一些自增id如reply_id和msg_id等等,使用list控制私信发送频率,使用zset进行全局各类id索引。 22 | 23 | 相对于mysql,nosql从来都是以性能彪悍著称,受限于作者本人电脑SSD硬盘容量的限制,没能测试千万级帖子的表现,测试中系统生成随机汉字的帖子,每个帖子随机分配3至5个充满随机汉字的回复,在灌满了约150W个帖子和600W个回复后,其性能还是非常彪悍,帖子和回复都是秒开。但在一些特定功能上,nosql还是暴露出了其缺陷,如帖子模糊搜索和根据用户名获取用户uid等功能,这方面还是要借助于MySQL,因此建立了两个MySQL表:user表用于存储用户信息,以便在注册时验证用户名存在、验证邮箱是否存在、根据用户名获取uid,thread表用于帖子标题分词,以便于站内的MATCH AGAINST搜索 24 | 25 | 在站内搜索方面上,部分网友觉得站内搜索太慢,是不是数据库的问题,在这里说明一下,分词采用的是[http://www.pullword.com/][8]的在线分词结果,相对于SCWS这类分词,pullword每天爬行各种语料,在分词结果上可以说是与时俱进,时刻保持着最新的词语结果,可以参见作者这篇博客[http://blog.sina.com.cn/s/blog_593af2a70102uw55.html][9],因此抛弃了SCWS转向pullword,发帖时,系统先进行分词处理,在站内搜索时,系统要分两步进行,先Ajax后端调用pullword api对搜索词进行分词,分词后再对mysql thread表进行MATCH AGAINST处理,因此,时间就耗在远程调用pullword api上,当然也可以换成SCWS时间更快,不过感觉站内搜索还是很鸡肋吧,大家都用site Google命令是不是 26 | 27 | 自己认为自己写的php框架才是全世界最好的php框架,此程序也是基于自己写的一个很tiny的php框架搭建而成的,系统全局用index.php作为唯一入口,system文件夹中common.php作为全局公用函数,config.php为全局公共配置文件,controller.php为全局公用所继承的父controller,model.php为全局公用所继承的父model,public文件夹存放全站静态文件,application文件夹中controllers文件夹包含全局各种控制文件,db文件夹包含mysql操作类和官方的ssdb类,models文件夹包含全局各种model文件,thumb文件夹用于头像的裁剪的类,views文件夹存放全站模板 28 | 29 | 30 | 31 | ---------- 32 | ## 安装Monster ## 33 | 34 | - 由于采用nosql作为主存储,因此Monster不支持虚拟主机,在VPS或服务器上,请先对mysql设定好ft_min_word_len=2,这样方便mysql全文检索。 35 | - 在MySQL中导入monster.sql 36 | - 按照ssdb官方文档[http://ssdb.io/docs/zh_cn/install.html][10]对服务器安装好ssdb 37 | - 由于Monster全局采用贴图库作为全站公用图片外链,需在[贴图库][11]申请贴图库的token,申请完毕后,按照system/config.php中的注释配置好config.php,Monster便配置完成了。 38 | - 请不要用windows主机运行,系统伪静态规则,Apache下直接使用系统自带的.htaccess文件,nginx下请在nginx配置文件中写入: 39 | ```location / { 40 | if (!-e $request_filename) { 41 | rewrite ^(.*)$ /index.php?s=$1 last; 42 | break; 43 | } 44 | } 45 | ``` 46 | 47 | [1]: http://www.domainideasgenerator.com 48 | [2]: https://plugins.jquery.com/cropbox/ 49 | [3]: https://github.com/devbridge/jQuery-Autocomplete 50 | [4]: https://github.com/daiying-zhang/jquery.jscrollbar 51 | [5]: http://timeago.yarp.com 52 | [6]: http://abpetkov.github.io/switchery/ 53 | [7]: http://ssdb.io/ 54 | [8]: http://www.pullword.com/ 55 | [9]: http://blog.sina.com.cn/s/blog_593af2a70102uw55.html 56 | [10]: http://ssdb.io/docs/zh_cn/install.html 57 | [11]: http://www.kekaoyun.com 58 | [12]: http://onehackoranother.com/projects/jquery/tipsy/ 59 | -------------------------------------------------------------------------------- /application/views/default/user_reply.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 |
17 |
18 | 22 |
23 |
24 | 对方关闭了回复列表浏览权限 25 |
26 | 0):foreach($reply as $v): 28 | ?> 29 |
30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 |
45 |
46 | 47 |
48 |
49 |
50 | 浏览() 51 | 回复() 52 | 投票() 53 | 收藏() 54 | 发表于 55 |
56 |
57 |
58 |
59 |
60 | 61 |
62 | 63 |
64 | 65 |
66 |
67 | 暂未回复任何帖子 68 |
69 | 70 |
71 |
72 | -------------------------------------------------------------------------------- /application/securimage/securimage_show.php: -------------------------------------------------------------------------------- 1 | 5 | * File: securimage_show.php
6 | * 7 | * Copyright (c) 2013, Drew Phillips 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without modification, 11 | * are permitted provided that the following conditions are met: 12 | * 13 | * - Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * - Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | * Any modifications to the library should be indicated clearly in the source code 32 | * to inform users that the changes are not a part of the original software.

33 | * 34 | * If you found this script useful, please take a quick moment to rate it.
35 | * http://www.hotscripts.com/rate/49400.html Thanks. 36 | * 37 | * @link http://www.phpcaptcha.org Securimage PHP CAPTCHA 38 | * @link http://www.phpcaptcha.org/latest.zip Download Latest Version 39 | * @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation 40 | * @copyright 2013 Drew Phillips 41 | * @author Drew Phillips 42 | * @version 3.5.2 (Feb 15, 2014) 43 | * @package Securimage 44 | * 45 | */ 46 | 47 | // Remove the "//" from the following line for debugging problems 48 | // error_reporting(E_ALL); ini_set('display_errors', 1); 49 | 50 | require_once dirname(__FILE__) . '/securimage.php'; 51 | 52 | $img = new Securimage(); 53 | 54 | // You can customize the image by making changes below, some examples are included - remove the "//" to uncomment 55 | 56 | //$img->ttf_file = './Quiff.ttf'; 57 | //$img->captcha_type = Securimage::SI_CAPTCHA_MATHEMATIC; // show a simple math problem instead of text 58 | //$img->case_sensitive = true; // true to use case sensitve codes - not recommended 59 | //$img->image_height = 30; // height in pixels of the image 60 | //$img->image_width = $img->image_height * M_E; // a good formula for image size based on the height 61 | //$img->perturbation = .75; // 1.0 = high distortion, higher numbers = more distortion 62 | //$img->image_bg_color = new Securimage_Color("#0099CC"); // image background color 63 | //$img->text_color = new Securimage_Color("#EAEAEA"); // captcha text color 64 | $img->num_lines = 4; // how many lines to draw over the image 65 | //$img->line_color = new Securimage_Color("#0000CC"); // color of lines over the image 66 | //$img->image_type = SI_IMAGE_JPEG; // render as a jpeg image 67 | //$img->signature_color = new Securimage_Color(rand(0, 64), 68 | // rand(64, 128), 69 | // rand(128, 255)); // random signature color 70 | 71 | // see securimage.php for more options that can be set 72 | 73 | // set namespace if supplied to script via HTTP GET 74 | if (!empty($_GET['namespace'])) $img->setNamespace($_GET['namespace']); 75 | 76 | 77 | $img->show(); // outputs the image and content headers to the browser 78 | // alternate use: 79 | // $img->show('/path/to/background_image.jpg'); 80 | -------------------------------------------------------------------------------- /application/views/default/user_top.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | 14 | 18 |
19 |
20 |
21 |
帖子
22 |
23 |
24 |
25 |
回复
26 |
27 |
28 |
29 |
收藏
30 |
31 |
32 |
33 | 48 |
49 | 通知 50 | 私信 51 | 帖子 52 | 回复 53 | 收藏 54 | 设置 55 | 头像 56 | 资料 57 | 私信 58 | uid==1):?>冻结账号 59 |
60 |
-------------------------------------------------------------------------------- /public/jquery.jscrollbar-2.0.0.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileOverview jquery.jscrollbar 3 | * @author daiying.zhang 4 | * @mail zdying@live.com/97532151@qq.com 5 | * @site http://imf2e.com 6 | * @version 2.0.0 7 | */ 8 | (function(f){function p(a,b,c,d){var e=this.opt,m=this.$con[0],g=this.$node.clone().appendTo("body").width(b).height(c).find(".jscrollbar"),n=e.showXBar&&m.scrollWidth>b,m=e.showYBar&&m.scrollHeight>c,k=0,k="",h="outer"===e.position?d:0;n&&m?k="xy":n?(k=g.css({height:c-h,zIndex:-1})[0].scrollHeight,k="x"+(e.showXBar&&k>c-h?"y":"")):m&&(k=g.css({width:b-h,zIndex:-1})[0].scrollWidth,k=(e.showXBar&&k>b-h?"x":"")+"y");this.scrollWidth=g[0].scrollWidth;this.scrollHeight=g[0].scrollHeight;g.parent().remove(); 9 | this.bars=k;e=this.delta=(this.bars.length-1)*d;g=this.thumbSize={x:q.call(this,"x"),y:q.call(this,"y")};this.maxPos={x:b-g.x-e,y:c-g.y-e};this.maxSPos={x:this.scrollWidth-b+e,y:this.scrollHeight-c+e};b=this.bars.split("");n=0;for(m=b.length;n").addClass(g).data("thumbType",g).css(e,d).append(f(r)[c.s](this.thumbSize[g]).data("type",g)).insertAfter(this.$con.css(e,"-="+("outer"===this.opt.position?d:0)));"inner"===this.opt.position&&a.find(".x,.y").css("background", 10 | "transparent")}function q(a){a=l[a];return Math.max(20,Math.pow(this.$con[a.s]()-this.delta,2)/this.$con[0][a.ss])}function s(){var a=this;this.$node.on("mousedown",".thumb",function(b){t.call(a,b,b.target);return!1}).on("click",".x,.y",function(b){var c=0,c=b.target,d=f.data(c,"thumbType"),e=l[d];c===this&&(c=b["page"+d.toUpperCase()]-f(c).offset()[e.p],a.scrollTo(d,c/a.maxPos[d]*a.maxSPos[d],a.opt.speed))});f(document).unbind("mouseup.jsb").bind("mouseup.jsb",function(){f(this).unbind("mousemove.jsb")}); 11 | u.call(this);"inner"===this.opt.position&&v.call(this)}function v(){var a=this.$node;a.hover(function(){a.find(".x,.y").stop().animate({opacity:1},200)},function(){a.find(".x,.y").stop().animate({opacity:0},500)}).mouseout()}function u(){var a=this.node,b=this,c=null;this.opt.mouseEvent&&(c=function(a){a=a||window.event;b.scrollBy(2===b.bars.length?"y":b.bars,-(a.wheelDelta?a.wheelDelta/120:-a.detail/3)*b.opt.mouseSpeed);f.event.fix(a).preventDefault()},a.addEventListener?(a.addEventListener("mousewheel", 12 | c),a.addEventListener("DOMMouseScroll",c)):a.onmousewheel=c)}function t(a,b){var c={X:a.pageX,Y:a.pageY},d=this,e={X:parseInt(f(b).css("left"))||0,Y:parseInt(f(b).css("top"))||0};f(document).bind("mousemove.jsb",function(a){var g=f.data(b,"type"),h=g.toUpperCase(),k=l[g].p;a=Math.min(Math.max(0,e[h]+(a["page"+h]-c[h])),d.maxPos[g]);f(b).css(k,a);d.scroll(g);return!1})}function h(a,b){this.node=a[0];this.$node=a;this.width=a.width();this.height=a.height();this.opt=b;this.plugID="jsb_"+Math.floor(9E3* 13 | Math.random()+1E3);var c=this.width,d=this.height,e=b.width;this.$node.css("overflow","hidden").addClass("jscrollbar").wrapInner(w.attr("id",this.plugID).css({width:c,height:d}));this.$con=f("#"+this.plugID);p.call(this,this.$node,c,d,e);s.call(this)}var w=f('
'),r='
',l={x:{s:"width",p:"left",sp:"scrollLeft",ss:"scrollWidth"},y:{s:"height",p:"top",sp:"scrollTop",ss:"scrollHeight"}};h.fn=h.prototype;h.fn.update=function(a){var b= 14 | this.$node,c=this.width=b.width(),d=this.height=b.height(),e=this.opt.width,f=this.getScrollPos("x"),g=this.getScrollPos("y");this.$node.find(".x,.y").remove();this.$con.css({width:c,height:d});p.call(this,b,c,d,e);switch(a){case "relative":f&&this.scrollTo("x",f);g&&this.scrollTo("y",g);break;case "bottom":this.scrollTo("y",this.maxSPos.y);break;case "right":this.scrollTo("x",this.maxSPos.x);break;default:this.scroll()}this.scroll()};h.fn.getThumbLocation=function(a){return parseFloat(this.$node.find("."+ 15 | a+" .thumb").css(l[a].p))||0};h.fn.getScrollPos=function(a){return this.$con[0][l[a].sp]};h.fn.scroll=function(a){void 0===a&&(a="x",this.scroll("y"));this.$con[0][l[a].sp]=this.getThumbLocation(a)/this.maxPos[a]*this.maxSPos[a]};h.fn.scrollBy=function(a,b){this.scrollTo(a,this.$con[0][l[a].sp]+b)};h.fn.scrollTo=function(a,b,c){b=Math.max(Math.min(this.maxSPos[a],b),0);var d={};d[l[a].sp]=b;this.$con.animate(d,c||0);this.$node.trigger("scroll",[a,b]);c=c||0;var d=l[a],e={};e[d.p]=this.maxPos[a]*(b|| 16 | this.$con[0][d.sp])/this.maxSPos[a];this.$node.find("."+a+" .thumb").animate(e,c)};f.fn.jscrollbar=function(a){if("string"===typeof a){var b=this.data("jsb_data");return b?b[a].apply(b,[].slice.call(arguments,1)):this}a=f.extend({},{width:8,position:"inner",showXBar:!0,showYBar:!0,mouseEvent:!0,mouseSpeed:30,speed:250},a);return this.each(function(){f.data(this,"jsb_data")||f.data(this,"jsb_data",new h(f(this),a))})};f.fn.jscrollbar.version="2.0.0"})(jQuery); -------------------------------------------------------------------------------- /application/views/default/err404.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404错误 6 | 10 | 11 | 12 | 13 |
14 | ERROR 404:文件没有找到 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /application/thumb/ThumbLib.inc.php: -------------------------------------------------------------------------------- 1 | 14 | * Copyright (c) 2009, Ian Selby/Gen X Design 15 | * 16 | * Author(s): Ian Selby 17 | * 18 | * Licensed under the MIT License 19 | * Redistributions of files must retain the above copyright notice. 20 | * 21 | * @author Ian Selby 22 | * @copyright Copyright (c) 2009 Gen X Design 23 | * @link http://phpthumb.gxdlabs.com 24 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 25 | * @version 3.0 26 | * @package PhpThumb 27 | * @filesource 28 | */ 29 | 30 | // define some useful constants 31 | define('THUMBLIB_BASE_PATH', dirname(__FILE__)); 32 | define('THUMBLIB_PLUGIN_PATH', THUMBLIB_BASE_PATH . '/thumb_plugins/'); 33 | define('DEFAULT_THUMBLIB_IMPLEMENTATION', 'gd'); 34 | 35 | /** 36 | * Include the PhpThumb Class 37 | */ 38 | require_once THUMBLIB_BASE_PATH . '/PhpThumb.inc.php'; 39 | /** 40 | * Include the ThumbBase Class 41 | */ 42 | require_once THUMBLIB_BASE_PATH . '/ThumbBase.inc.php'; 43 | /** 44 | * Include the GdThumb Class 45 | */ 46 | require_once THUMBLIB_BASE_PATH . '/GdThumb.inc.php'; 47 | 48 | /** 49 | * PhpThumbFactory Object 50 | * 51 | * This class is responsible for making sure everything is set up and initialized properly, 52 | * and returning the appropriate thumbnail class instance. It is the only recommended way 53 | * of using this library, and if you try and circumvent it, the sky will fall on your head :) 54 | * 55 | * Basic use is easy enough. First, make sure all the settings meet your needs and environment... 56 | * these are the static variables defined at the beginning of the class. 57 | * 58 | * Once that's all set, usage is pretty easy. You can simply do something like: 59 | * $thumb = PhpThumbFactory::create('/path/to/file.png'); 60 | * 61 | * Refer to the documentation for the create function for more information 62 | * 63 | * @package PhpThumb 64 | * @subpackage Core 65 | */ 66 | class PhpThumbFactory 67 | { 68 | /** 69 | * Which implemenation of the class should be used by default 70 | * 71 | * Currently, valid options are: 72 | * - imagick 73 | * - gd 74 | * 75 | * These are defined in the implementation map variable, inside the create function 76 | * 77 | * @var string 78 | */ 79 | public static $defaultImplemenation = DEFAULT_THUMBLIB_IMPLEMENTATION; 80 | /** 81 | * Where the plugins can be loaded from 82 | * 83 | * Note, it's important that this path is properly defined. It is very likely that you'll 84 | * have to change this, as the assumption here is based on a relative path. 85 | * 86 | * @var string 87 | */ 88 | public static $pluginPath = THUMBLIB_PLUGIN_PATH; 89 | 90 | /** 91 | * Factory Function 92 | * 93 | * This function returns the correct thumbnail object, augmented with any appropriate plugins. 94 | * It does so by doing the following: 95 | * - Getting an instance of PhpThumb 96 | * - Loading plugins 97 | * - Validating the default implemenation 98 | * - Returning the desired default implementation if possible 99 | * - Returning the GD implemenation if the default isn't available 100 | * - Throwing an exception if no required libraries are present 101 | * 102 | * @return GdThumb 103 | * @uses PhpThumb 104 | * @param string $filename The path and file to load [optional] 105 | */ 106 | public static function create ($filename = null, $options = array(), $isDataStream = false) 107 | { 108 | // map our implementation to their class names 109 | $implementationMap = array 110 | ( 111 | 'imagick' => 'ImagickThumb', 112 | 'gd' => 'GdThumb' 113 | ); 114 | 115 | // grab an instance of PhpThumb 116 | $pt = PhpThumb::getInstance(); 117 | // load the plugins 118 | $pt->loadPlugins(self::$pluginPath); 119 | 120 | $toReturn = null; 121 | $implementation = self::$defaultImplemenation; 122 | 123 | // attempt to load the default implementation 124 | if ($pt->isValidImplementation(self::$defaultImplemenation)) 125 | { 126 | $imp = $implementationMap[self::$defaultImplemenation]; 127 | $toReturn = new $imp($filename, $options, $isDataStream); 128 | } 129 | // load the gd implementation if default failed 130 | else if ($pt->isValidImplementation('gd')) 131 | { 132 | $imp = $implementationMap['gd']; 133 | $implementation = 'gd'; 134 | $toReturn = new $imp($filename, $options, $isDataStream); 135 | } 136 | // throw an exception if we can't load 137 | else 138 | { 139 | throw new Exception('You must have either the GD or iMagick extension loaded to use this library'); 140 | } 141 | 142 | $registry = $pt->getPluginRegistry($implementation); 143 | $toReturn->importPlugins($registry); 144 | return $toReturn; 145 | } 146 | } -------------------------------------------------------------------------------- /public/css/m.css: -------------------------------------------------------------------------------- 1 | .round{border-radius: 100%;} 2 | .clear{clear: both} 3 | .left{float: left} 4 | .right{float: right} 5 | .overflow {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;} 6 | .none{display: none} 7 | 8 | .bar-nav{background: #fafafa;} 9 | .card{margin: .5rem 0;box-shadow: none;box-shadow: 0px 0.05rem 0.05rem rgba(0,0,0,.1)} 10 | .card-avatar{width: 1.5rem;height: 1.5rem;vertical-align: middle;margin-right: 0.3rem} 11 | .thread_abstract{color: #888;} 12 | .page_btn{width: 50%;float:left;text-align: center} 13 | #zero span{font-size: 5rem;color: #eee} 14 | #zero_info{color: #ccc;font-size: .8rem;margin-top: 1rem;} 15 | #zero{height: 13rem;} 16 | .thread_title{color: #000;} 17 | .link .icon{margin-right: 0.2rem} 18 | #post_new_thread{border-color: #fff;color: #fff;} 19 | #post_new_thread span{margin-right: 0.4rem;} 20 | .panel_info_wrapper{display: block;color: #fff;margin-top: 1.4rem} 21 | #panel_login_btn{margin-bottom: 1.2rem;color: #fff;border-color: #fff;opacity: 0.7} 22 | #panel_register_btn{color: #fff;border-color: #fff;opacity: 0.7} 23 | #login_captcha{height: 2.15rem;max-width: 4rem} 24 | #up span{font-size: 4rem;color:#bbb} 25 | #up div{color: #9f9f9f} 26 | #pub_title{width: 100%;height: 2.5rem;border:0px;text-indent:0.3rem;border-bottom: 1px solid #eee} 27 | #category_select{width: 100%;height: 2.5rem;text-indent:0.3rem;line-height:2.5rem;border-top: 1px solid #eee;border-bottom: 1px solid #eee;border-left:0px;border-right:0px;text-align: left;color: #aaa} 28 | #pub_content{width: 100%;height:100%;border:0px;border-top:1px solid #eee;margin-top: 0.5rem;text-indent:0.3rem;} 29 | .category_block{margin-top: 2.2rem} 30 | .actions-modal-button a{font-size: 0.8rem} 31 | .r{border-radius:100%;} 32 | #user_top_avatar{padding: 0.8rem 0;} 33 | #user_top_name{display: block;margin-top: 0.4rem;margin-bottom:0.4rem;font-size: 0.8rem} 34 | .user_top_wrapper h2{font-weight: normal;font-size: inherit;margin: 0.4rem 0 0 0;} 35 | #user_tab a{ font-size: 0.7rem} 36 | .setting_ok{width: 12%!important;font-size: 0.75rem!important;text-align: right;color: #0894ec} 37 | #user_setting_card .item-input input{ font-size: 0.75rem!important;} 38 | .item-input span{font-size: 0.75rem;margin-left: 0.3rem;color: #aaa} 39 | .setting_checkbox{width: 20%!important;} 40 | .actions-modal-button .icon{margin-right: 0.4rem} 41 | #msg{margin:0;font-size: 0.75rem} 42 | #dialog_outer{position: absolute;width: 100%;height: 100%;top: 0;left: 0;padding: 2.9rem 0.5rem 0 0.5rem} 43 | #dialog_list{padding-bottom: 2.4rem} 44 | .msg_wrapper{margin-bottom: 1rem;} 45 | .msg_wrapper_avatar img{width:13%;border-radius: 100%;} 46 | 47 | .msglist_left .msg_wrapper_avatar img{float: left} 48 | .msg_wrapper_content{max-width: 66%; padding: 10px;border-radius: 3px;line-height: 20px;} 49 | .msglist_left .msg_wrapper_content{background: #F2F5F6;float: left;margin-left:17px;color: #5C6367} 50 | .msg_content{font-size: 0.7rem;line-height: 22px;} 51 | .msglist_left .msg_arrow{ display: block;width: 0;height: 0;line-height: 0;border: 9px dashed #F2F5F6;border-right-style: solid;border-left: none;border-top-color: transparent;border-bottom-color: transparent;border-right-color: #F2F5F6;margin: 0px auto;margin-top: 3px;margin-left: -18px;position: absolute;} 52 | .msglist_left .msg_wrapper_time{float: right;color: #bbb;margin-top:0.75rem;font-size: 0.6rem;} 53 | .fixed{position: fixed} 54 | .msglist_right .msg_wrapper_avatar img{float: right} 55 | .msglist_right .msg_wrapper_content{background: #00A7EB;float: right;margin-right:0.6rem;color: #fff;text-shadow: 0px 0px 1px rgba(0, 167, 235,.4);float: right} 56 | .msglist_right .msg_arrow{ display: block; 57 | width: 0; 58 | height: 0; 59 | line-height: 0; 60 | border: 9px dashed #00A7EB; 61 | border-left-style: solid; 62 | border-right: none; 63 | border-top-color: transparent; 64 | border-bottom-color: transparent; 65 | border-left-color: #00A7EB; 66 | margin: 0px auto; 67 | margin-top: 3px; 68 | margin-right: -17px; 69 | float: right; 70 | } 71 | .msglist_right .msg_wrapper_time{float: left;color: #bbb;margin-top:0.75rem;font-size: 0.6rem;} 72 | #msg_bottom{position: fixed;bottom: 0;left:0;width: 100%;padding-right: 1rem;height: 2.2rem;border-top: 1px solid #eee;background: #fff;} 73 | #msg_input{border: 0;float: left;height: 100%;width:94%;font-size: 0.7rem;margin-left: 0.3rem} 74 | #send_btn{font-size: 1rem;line-height: 2.2rem;position: fixed;right: 0.5rem;bottom:0rem;z-index: 100} 75 | #prev_load_more{text-align: center;font-size: 0.7rem;padding: 0.2rem 0 0.4rem 0;color: #999} 76 | #prev_load_more i{margin-right: 0.4rem} 77 | .dot{width: 0.4rem;height: 0.4rem;background: #f00;position: absolute;margin-top: 0.5rem;margin-left: -0.3rem} 78 | .nomargin{margin: 0!important;} 79 | select{border: 0;background: #fff;width: 100%;text-align: left;color: #aaa;text-indent: 0.2rem;padding-top: 0.7rem;-webkit-appearance: none;-moz-appearance: none;text-overflow: '';} 80 | .pub_opt{width: 2rem;height: 1.5rem;overflow: hidden;position:absolute;bottom: 0.5rem;left: 0rem;z-index: 99999} 81 | .pub_opt .icon{font-size: 1rem;color: #00A7EB;position: absolute;} 82 | .pub_opt input[type=file]{font-size: 5rem;position: absolute;opacity: 0} 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /application/views/default/header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <?php echo $title; ?> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | 26 |
27 |
28 | 65 |
66 |
67 | 78 |
79 |
总会员:
80 |
总帖子数:
81 |
82 |
83 |
84 |
85 |
-------------------------------------------------------------------------------- /public/jquery.caret.min.js: -------------------------------------------------------------------------------- 1 | /*! jquery.caret 2015-02-01 */ 2 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return a.returnExportsGlobal=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){"use strict";var b,c,d,e,f,g,h,i,j,k,l;k="caret",b=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.setPos=function(){return this.domInputor},b.prototype.getIEPosition=function(){return this.getPosition()},b.prototype.getPosition=function(){var a,b;return b=this.getOffset(),a=this.$inputor.offset(),b.left-=a.left,b.top-=a.top,b},b.prototype.getOldIEPos=function(){var a,b;return b=h.selection.createRange(),a=h.body.createTextRange(),a.moveToElementText(this.domInputor),a.setEndPoint("EndToEnd",b),a.text.length},b.prototype.getPos=function(){var a,b,c;return(c=this.range())?(a=c.cloneRange(),a.selectNodeContents(this.domInputor),a.setEnd(c.endContainer,c.endOffset),b=a.toString().length,a.detach(),b):h.selection?this.getOldIEPos():void 0},b.prototype.getOldIEOffset=function(){var a,b;return a=h.selection.createRange().duplicate(),a.moveStart("character",-1),b=a.getBoundingClientRect(),{height:b.bottom-b.top,left:b.left,top:b.top}},b.prototype.getOffset=function(){var b,c,d,e,f;return j.getSelection&&(d=this.range())?(d.endOffset-1>0&&d.endContainer===!this.domInputor&&(b=d.cloneRange(),b.setStart(d.endContainer,d.endOffset-1),b.setEnd(d.endContainer,d.endOffset),e=b.getBoundingClientRect(),c={height:e.height,left:e.left+e.width,top:e.top},b.detach()),c&&0!==(null!=c?c.height:void 0)||(b=d.cloneRange(),f=a(h.createTextNode("|")),b.insertNode(f[0]),b.selectNode(f[0]),e=b.getBoundingClientRect(),c={height:e.height,left:e.left,top:e.top},f.remove(),b.detach())):h.selection&&(c=this.getOldIEOffset()),c&&(c.top+=a(j).scrollTop(),c.left+=a(j).scrollLeft()),c},b.prototype.range=function(){var a;if(j.getSelection)return a=j.getSelection(),a.rangeCount>0?a.getRangeAt(0):null},b}(),c=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.getIEPos=function(){var a,b,c,d,e,f,g;return b=this.domInputor,f=h.selection.createRange(),e=0,f&&f.parentElement()===b&&(d=b.value.replace(/\r\n/g,"\n"),c=d.length,g=b.createTextRange(),g.moveToBookmark(f.getBookmark()),a=b.createTextRange(),a.collapse(!1),e=g.compareEndPoints("StartToEnd",a)>-1?c:-g.moveStart("character",-c)),e},b.prototype.getPos=function(){return h.selection?this.getIEPos():this.domInputor.selectionStart},b.prototype.setPos=function(a){var b,c;return b=this.domInputor,h.selection?(c=b.createTextRange(),c.move("character",a),c.select()):b.setSelectionRange&&b.setSelectionRange(a,a),b},b.prototype.getIEOffset=function(a){var b,c,d,e;return c=this.domInputor.createTextRange(),a||(a=this.getPos()),c.move("character",a),d=c.boundingLeft,e=c.boundingTop,b=c.boundingHeight,{left:d,top:e,height:b}},b.prototype.getOffset=function(b){var c,d,e;return c=this.$inputor,h.selection?(d=this.getIEOffset(b),d.top+=a(j).scrollTop()+c.scrollTop(),d.left+=a(j).scrollLeft()+c.scrollLeft(),d):(d=c.offset(),e=this.getPosition(b),d={left:d.left+e.left-c.scrollLeft(),top:d.top+e.top-c.scrollTop(),height:e.height})},b.prototype.getPosition=function(b){var c,e,f,g,h,i,j;return c=this.$inputor,g=function(b){return a("
").text(b).html().replace(/\r\n|\r|\n/g,"
").replace(/\s/g," ")},void 0===b&&(b=this.getPos()),j=c.val().slice(0,b),f=c.val().slice(b),h=""+g(j)+"",h+="|",h+=""+g(f)+"",i=new d(c),e=i.create(h).rect()},b.prototype.getIEPosition=function(a){var b,c,d,e,f;return d=this.getIEOffset(a),c=this.$inputor.offset(),e=d.left-c.left,f=d.top-c.top,b=d.height,{left:e,top:f,height:b}},b}(),d=function(){function b(a){this.$inputor=a}return b.prototype.css_attr=["borderBottomWidth","borderLeftWidth","borderRightWidth","borderTopStyle","borderRightStyle","borderBottomStyle","borderLeftStyle","borderTopWidth","boxSizing","fontFamily","fontSize","fontWeight","height","letterSpacing","lineHeight","marginBottom","marginLeft","marginRight","marginTop","outlineWidth","overflow","overflowX","overflowY","paddingBottom","paddingLeft","paddingRight","paddingTop","textAlign","textOverflow","textTransform","wordBreak","wordWrap"],b.prototype.mirrorCss=function(){var b,c=this;return b={position:"absolute",left:-9999,top:0,zIndex:-2e4,whiteSpace:"pre-wrap"},"TEXTAREA"===this.$inputor.prop("tagName")&&this.css_attr.push("width"),a.each(this.css_attr,function(a,d){return b[d]=c.$inputor.css(d)}),b},b.prototype.create=function(b){return this.$mirror=a("
"),this.$mirror.css(this.mirrorCss()),this.$mirror.html(b),this.$inputor.after(this.$mirror),this},b.prototype.rect=function(){var a,b,c;return a=this.$mirror.find("#caret"),b=a.position(),c={left:b.left,top:b.top,height:a.height()},this.$mirror.remove(),c},b}(),e={contentEditable:function(a){return!(!a[0].contentEditable||"true"!==a[0].contentEditable)}},g={pos:function(a){return a||0===a?this.setPos(a):this.getPos()},position:function(a){return h.selection?this.getIEPosition(a):this.getPosition(a)},offset:function(a){var b;return b=this.getOffset(a)}},h=null,j=null,i=null,l=function(a){var b;return(b=null!=a?a.iframe:void 0)?(i=b,j=b.contentWindow,h=b.contentDocument||j.document):(i=void 0,j=window,h=document)},f=function(a){var b;h=a[0].ownerDocument,j=h.defaultView||h.parentWindow;try{return i=j.frameElement}catch(c){b=c}},a.fn.caret=function(d,f,h){var i;return g[d]?(a.isPlainObject(f)?(l(f),f=void 0):l(h),i=e.contentEditable(this)?new b(this):new c(this),g[d].apply(i,[f])):a.error("Method "+d+" does not exist on jQuery.caret")},a.fn.caret.EditableCaret=b,a.fn.caret.InputCaret=c,a.fn.caret.Utils=e,a.fn.caret.apis=g}); -------------------------------------------------------------------------------- /application/models/userModel.php: -------------------------------------------------------------------------------- 1 | ssdb->hget($this->prefix.$uid,'username'); 15 | if($username!=null){ 16 | return $username; 17 | }else{ 18 | return false; 19 | } 20 | } 21 | /* 22 | * get uid by username 23 | * @param char $username 24 | */ 25 | public function getUidByUsername($username){ 26 | $uid=$this->mysql->table('user')->where(array('username'=>$username))->field('uid')->find(); 27 | if(isint($uid['uid'])){ 28 | return $uid['uid']; 29 | }else{ 30 | return false; 31 | } 32 | } 33 | /* 34 | * get username attibution by uid, e.g. username email reg_ip ctime 35 | * @param int $uid 36 | * @param char or array $attrname 37 | */ 38 | public function getAttrByUid($uid,$attrname){ 39 | if(is_array($attrname)){ 40 | $attr=$this->ssdb->multi_hget($this->prefix.$uid,$attrname); 41 | return $attr; 42 | }else{ 43 | $attr=$this->ssdb->hget($this->prefix.$uid,$attrname); 44 | return $attr; 45 | } 46 | } 47 | /* 48 | * get username attibution by attrname, e.g. email reg_ip ctime, but not including uid 49 | * @param char $username 50 | * @param char or array $attrname 51 | */ 52 | public function getAttrByUsername($username,$attrname){ 53 | $uid=$this->getUidByUsername($username); 54 | if(isint($uid)){ 55 | $attr=$this->getAttrByUid($uid,$attrname); 56 | if($attr!=null){ 57 | return $attr; 58 | }else{ 59 | return false; 60 | } 61 | }else{ 62 | return false; 63 | } 64 | } 65 | /* 66 | * get user info by uid 67 | * @param int $uid 68 | */ 69 | public function getUserInfoByUid($uid){ 70 | $userinfo=$this->ssdb->hgetall($this->prefix.$uid); 71 | if($userinfo!=null){ 72 | return $userinfo; 73 | }else{ 74 | return false; 75 | } 76 | } 77 | /* 78 | * get user info by username 79 | * @param char $username 80 | */ 81 | public function getUserInfoByUsername($username){ 82 | $uid=$this->getUidByUsername($username); 83 | if(isint($uid)){ 84 | $userinfo=$this->getUserInfoByUid($uid); 85 | return $userinfo; 86 | }else{ 87 | return false; 88 | } 89 | } 90 | /* 91 | * check user has the attrbution e.g. notice msg 92 | * @param int $uid 93 | * @param char $attr 94 | */ 95 | public function hasAttr($uid,$attr){ 96 | return $this->ssdb->hexists($this->prefix.$uid,$attr); 97 | } 98 | /* 99 | * set user attribution 100 | * @param int $int 101 | * @param char $attr 102 | * @param any $value 103 | */ 104 | public function setUserAttr($uid,$attr,$value){ 105 | $result=$this->ssdb->hset($this->prefix.$uid,$attr,$value); 106 | return $result; 107 | } 108 | /* 109 | * @param int $uid 110 | * @param array $attr 111 | */ 112 | public function setUserAttrs($uid,$attr){ 113 | $result=$this->ssdb->multi_hset($this->prefix.$uid,$attr); 114 | if($result==null){ 115 | return false; 116 | }else{ 117 | return true; 118 | } 119 | } 120 | /* 121 | * @param int $uid 122 | */ 123 | public function freezeUser($uid){ 124 | return $this->ssdb->multi_hdel($this->prefix.$uid,array('new_msg','new_notice')); 125 | } 126 | /* 127 | * increase user attibution value e.g. notice msg 128 | * @param int $int 129 | * @param char $attr 130 | * @param int $incr_num 131 | */ 132 | public function incrUserAttr($uid,$attr,$incr_num=1){ 133 | return $this->ssdb->hincr($this->prefix.$uid,$attr,$incr_num); 134 | } 135 | /* 136 | * @param char $words 137 | */ 138 | public function searchUser($words){ 139 | $where['username'] = array('like','%'.$words.'%'); 140 | return $this->mysql->table('user')->where($where)->field('uid,username')->limit(5)->select(); 141 | } 142 | /* 143 | * @param int $my_uid 144 | * @param int $hid_uid 145 | */ 146 | public function getUserVoteInteraction($my_uid,$his_uid){ 147 | return $this->ssdb->get($this->vote_interaction_prefix.$my_uid.'_'.$his_uid); 148 | } 149 | /* 150 | * @param int $my_uid 151 | * @param int $hid_uid 152 | */ 153 | public function getUserReplyInteraction($my_uid,$his_uid){ 154 | return $this->ssdb->get($this->reply_interaction_prefix.$my_uid.'_'.$his_uid); 155 | } 156 | /* 157 | * @param int $my_uid 158 | * @param int $hid_uid 159 | */ 160 | public function incrUserVoteInteraction($my_uid,$his_uid){ 161 | $i=$this->vote_interaction_prefix.$my_uid.'_'.$his_uid; 162 | $this->ssdb->exists($i)?$this->ssdb->incr($i):$this->ssdb->set($i,1); 163 | } 164 | /* 165 | * @param int $my_uid 166 | * @param int $hid_uid 167 | */ 168 | public function incrUserReplyInteraction($my_uid,$his_uid){ 169 | $i=$this->reply_interaction_prefix.$my_uid.'_'.$his_uid; 170 | $this->ssdb->exists($i)?$this->ssdb->incr($i):$this->ssdb->set($i,1); 171 | } 172 | } 173 | ?> -------------------------------------------------------------------------------- /system/controller.php: -------------------------------------------------------------------------------- 1 | config=$config; 11 | $classname=str_replace('Controller','',get_class($this)); 12 | if(file_exists(APP_DIR .'models'.DIRECTORY_SEPARATOR. strtolower($classname) .'Model.php')){ 13 | $this->model=$this->model($classname); 14 | } 15 | $this->set('siteCounter',$this->model('main')->getSiteCounter()); 16 | $cookie=decrypt($_COOKIE[$this->config['cookie_prefix'].'Auth']); 17 | if(isint($cookie)&&$_COOKIE[$this->config['cookie_prefix'].'username']!=''){ 18 | $this->uid=$cookie; 19 | $this->username=urldecode($_COOKIE[$this->config['cookie_prefix'].'username']); 20 | if($_COOKIE[$this->config['cookie_prefix'].'avatar_small']==''){ 21 | $avatar=$this->model('user')->getAttrByUid($cookie,array('small_avatar','big_avatar')); 22 | if($avatar['small_avatar']==''||$avatar['big_avatar']==''){ 23 | setcookie($this->config['cookie_prefix'].'avatar_big',$this->config['default_big_avatar'],0,'/'); 24 | setcookie($this->config['cookie_prefix'].'avatar_small',$this->config['default_small_avatar'],0,'/'); 25 | }else{ 26 | setcookie($this->config['cookie_prefix'].'avatar_small',$avatar['small_avatar'],0,'/'); 27 | setcookie($this->config['cookie_prefix'].'avatar_big',$avatar['big_avatar'],0,'/'); 28 | } 29 | } 30 | $new_inform=$this->model('user')->getAttrByUid($cookie,array('new_notice','new_msg')); 31 | if(count($new_inform)==0&&$_COOKIE[$this->config['cookie_prefix'].'Auth']!=''){//account has been deleted 32 | setcookie($this->config['cookie_prefix'].'Auth','',time()-3600,'/'); 33 | setcookie($this->config['cookie_prefix'].'avatar_big','',time()-3600,'/'); 34 | setcookie($this->config['cookie_prefix'].'avatar_small','',time()-3600,'/'); 35 | setcookie($this->config['cookie_prefix'].'user_info','',time()-3600,'/'); 36 | header('location:'.$this->config['site']); 37 | } 38 | $new_inform['new_msg']=json_decode($new_inform['new_msg'],true); 39 | $this->set('new_inform',$new_inform); 40 | if($_COOKIE[$this->config['cookie_prefix'].'user_info']==''){ 41 | $user_attrs=$this->model('user')->getAttrByUid($cookie,array('thread_num','reply_num','collect_num')); 42 | setcookie($this->config['cookie_prefix'].'user_info',$user_attrs['thread_num'].'_'.$user_attrs['reply_num'].'_'.$user_attrs['collect_num'],0,'/'); 43 | } 44 | } 45 | } 46 | public function model($name){ 47 | require_once(APP_DIR .'models'.DIRECTORY_SEPARATOR. strtolower($name) .'Model.php'); 48 | $name.='Model'; 49 | $model = new $name; 50 | return $model; 51 | } 52 | public function set($var, $val){ 53 | $this->pageVars[$var] = $val; 54 | } 55 | public function render($template){ 56 | $tpl_cache=ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl'.DIRECTORY_SEPARATOR.$this->config['theme'].DIRECTORY_SEPARATOR.$template.'.php'; 57 | $tpl=APP_DIR.'views'.DIRECTORY_SEPARATOR . $this->config['theme'].DIRECTORY_SEPARATOR . strtolower($template).'.php'; 58 | if(!file_exists($tpl_cache)){ 59 | //start to create template cache dir 60 | if(!is_dir(ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl'.DIRECTORY_SEPARATOR.$this->config['theme'])){ 61 | mkdir(ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl',0755); 62 | mkdir(ROOT_DIR.'runtime'.DIRECTORY_SEPARATOR.'tpl'.DIRECTORY_SEPARATOR.$this->config['theme'],0755); 63 | } 64 | copy($tpl,$tpl_cache); 65 | $match=true; 66 | while($match){ 67 | $tpl_content=file_get_contents($tpl_cache); 68 | preg_match_all('/(include|require|include_once|require_once)\((\"|\')(.*?)(\"|\')\)(\s*)\;/',$tpl_content,$matches); 69 | $pattern=array(); 70 | $replace=array(); 71 | if(count($matches[0])>0){ 72 | foreach($matches[0] as $k=>$v){ 73 | $pattern[]='/\<\?php(\s*)'.preg_quote($v).'(\s*)\?\>/'; 74 | $replace[]=file_get_contents(APP_DIR .'views'.DIRECTORY_SEPARATOR.$this->config['theme'].DIRECTORY_SEPARATOR.$matches[3][$k]); 75 | } 76 | $tpl_temp=preg_replace($pattern,$replace,$tpl_content); 77 | file_put_contents($tpl_cache,$tpl_temp); 78 | }else{ 79 | $match=false; 80 | } 81 | } 82 | } 83 | extract($this->pageVars); 84 | ob_start(); 85 | if(CACHE_ON){ 86 | include($tpl_cache); 87 | }else{ 88 | include($tpl); 89 | } 90 | echo ob_get_clean(); 91 | } 92 | function ajaxNeedLogin(){ 93 | if(!$this->uid){ 94 | $callback=array( 95 | 'status'=>false, 96 | 'msg'=>'登录后才能执行此操作哟~' 97 | ); 98 | echo json_encode($callback); 99 | exit; 100 | } 101 | } 102 | function needLogin(){ 103 | if(!$this->uid){ 104 | header('location:'.$this->config['site']); 105 | exit; 106 | } 107 | } 108 | function err404(){ 109 | header("HTTP/1.1 404 Not Found"); 110 | require_once(APP_DIR . 'views/default/err404.php'); 111 | exit; 112 | } 113 | } 114 | ?> -------------------------------------------------------------------------------- /application/controllers/mainController.php: -------------------------------------------------------------------------------- 1 | model->getThreads('hot_thread',0,1); 9 | $thread=pagination($thread_list,1,0,$this->config['thread_per_page']); 10 | $this->set('thread_list',$thread['arr']); 11 | $next=$thread['next']!=''?url('main/threads',array('type'=>'hot','last_id'=>$thread['next'],'direction'=>1)):''; 12 | $this->set('prev',''); 13 | $this->set('next',$next); 14 | $this->set('title','热门帖子 | '.$this->config['shortname']); 15 | $this->set('navbar_cur','hot'); 16 | $this->render('index'); 17 | } 18 | public function threads($type,$last_id,$direction){ 19 | /*$thread_model=$this->model('thread'); 20 | $reply_model=$this->model('reply'); 21 | for($i=0;$i<3;$i++){ 22 | $rand_uid=rand(2,4); 23 | $u_name=array('abc','def','ghi'); 24 | $t=$thread_model->addThread(genstr(rand(15,30)),rand(1,7),genstr(rand(20,50)),$rand_uid,$u_name[$rand_uid]); 25 | if($t['status']){ 26 | $thread_id=$t['msg']; 27 | $reply_model->postReply($thread_id,genstr(rand(10,30)),rand(2,4)); 28 | } 29 | }*/ 30 | $type=x($type); 31 | $keys=array('hot'=>'热门','latest'=>'最新'); 32 | !array_key_exists($type,$keys)&&exit; 33 | $last_id=intval($last_id); 34 | $direction=intval($direction); 35 | $convert_keys=array('hot'=>'hot_thread','latest'=>'thread'); 36 | $thread_list=$this->model->getThreads($convert_keys[$type],$last_id,$direction); 37 | $thread=pagination($thread_list,$direction,$last_id,$this->config['thread_per_page']); 38 | $prev=$thread['prev']!=''?url('main/threads',array('type'=>$type,'last_id'=>$thread['prev'],'direction'=>0)):''; 39 | $next=$thread['next']!=''?url('main/threads',array('type'=>$type,'last_id'=>$thread['next'],'direction'=>1)):''; 40 | $this->set('thread_list',$thread['arr']); 41 | $this->set('prev',$prev); 42 | $this->set('next',$next); 43 | $this->set('breadcrumb',' ›
  • 44 | 45 |

    '.$keys[$type].'帖子

    46 |
    47 | 48 |
  • '); 49 | $this->set('keywords',$type.' 帖子'); 50 | $this->set('title',$keys[$type].'帖子 | '.$this->config['shortname']); 51 | $this->set('navbar_cur',$type); 52 | $this->render('index'); 53 | } 54 | public function category($category_id,$last_id,$direction){ 55 | $category_id=intval($category_id); 56 | !array_key_exists($category_id,$this->config['category'])&&exit; 57 | $category=$this->config['category'][$category_id]; 58 | $last_id=intval($last_id); 59 | $direction=intval($direction); 60 | $thread_list=$this->model->getThreads('category'.$category_id,$last_id,$direction); 61 | $thread=pagination($thread_list,$direction,$last_id,$this->config['thread_per_page']); 62 | $prev=$thread['prev']!=''?url('main/category',array('category'=>$category,'last_id'=>$thread['prev'],'direction'=>0)):''; 63 | $next=$thread['next']!=''?url('main/category',array('category'=>$category,'last_id'=>$thread['next'],'direction'=>1)):''; 64 | $this->set('thread_list',$thread['arr']); 65 | $this->set('prev',$prev); 66 | $this->set('next',$next); 67 | $this->set('category',$category); 68 | $this->set('navbar_cur','latest'); 69 | $this->set('breadcrumb',' ›
  • 70 | 71 |

    '.$category.'

    72 |
    73 | 74 |
  • '); 75 | $this->set('title',$category.'分类下最新帖子 | '.$this->config['shortname']); 76 | $this->set('keywords',$category); 77 | $this->set('description',$category.'分类下最新帖子'); 78 | $this->render('index'); 79 | } 80 | public function pubUpload(){ 81 | parent::ajaxNeedLogin(); 82 | $image_size=getimagesize($_FILES['jUploaderFile']['tmp_name']); 83 | if($image_size[0]>0&&$image_size[1]>0){//check if is image 84 | $ext=pathinfo($_FILES['jUploaderFile']['name'],PATHINFO_EXTENSION);//get image extension 85 | $upload_name=ROOT_DIR.'public'.DIRECTORY_SEPARATOR.'temp_upload_dir'.DIRECTORY_SEPARATOR.uniqid().'_'.$this->uid.'.'.$ext; 86 | if(move_uploaded_file($_FILES['jUploaderFile']['tmp_name'],$upload_name)){ 87 | $image=upload_file($upload_name);// upload to tietuku.cn 88 | unlink($upload_name);//delete temp uploaded image 89 | if(strstr($image,'piimg.com')){//check callback result is an image or not 90 | $callback=array( 91 | 'status'=>true, 92 | 'msg'=>$image 93 | ); 94 | }else{ 95 | $callback=array( 96 | 'status'=>false, 97 | 'msg'=>'上传到贴图库失败,请稍后重试' 98 | ); 99 | } 100 | }else{ 101 | $callback=array( 102 | 'status'=>false, 103 | 'msg'=>'内部错误,请稍后重试' 104 | ); 105 | } 106 | }else{ 107 | $callback=array( 108 | 'status'=>false, 109 | 'msg'=>'不是标准的图片格式' 110 | ); 111 | } 112 | echo json_encode($callback); 113 | } 114 | } 115 | ?> 116 | -------------------------------------------------------------------------------- /application/views/default/user_setting.php: -------------------------------------------------------------------------------- 1 | 2 | 48 |
    49 |
    50 | 51 |
    52 |
    个人介绍:
    确 定
    53 |
    个人网址:
    确 定
    54 |
    个人微博:
    确 定
    55 |
    Dribbble:
    确 定
    56 |
    GitHub:
    确 定
    57 |
    Facebook:
    确 定
    58 |
    Twitter:
    确 定
    59 |
    禁止网友在我的个人主页查看我的帖子列表
    checked class="js-switch"/>
    60 |
    禁止网友在我的个人主页查看我的回复列表
    checked class="js-switch"/>
    61 |
    禁止网友在我的个人主页查看我的收藏列表
    checked class="js-switch"/>
    62 |
    禁止网友给我发送私信
    checked class="js-switch"/>
    63 |
    当有人回复我时不通知我
    checked class="js-switch"/>
    64 |
    当有人@我时不通知我
    checked class="js-switch"/>
    65 |
    当有人赞我时不通知我
    checked class="js-switch"/>
    66 |
    67 |
    68 |
    69 | -------------------------------------------------------------------------------- /application/controllers/accountController.php: -------------------------------------------------------------------------------- 1 | uid)&&exit;//if user has already signed in 13 | include_once ROOT_DIR.'application'.DIRECTORY_SEPARATOR.'securimage'.DIRECTORY_SEPARATOR.'securimage.php'; 14 | $securimage = new Securimage();//for captcha 15 | $_POST==NULL&&exit; 16 | $username=x($_POST['username']); 17 | $email=x($_POST['email']); 18 | $pwd=x($_POST['pwd']); 19 | $captcha=x($_POST['captcha']); 20 | if($username==''||strlen($username)>20){ 21 | $callback=array( 22 | 'status'=>false, 23 | 'msg'=>'请重新输入用户名' 24 | ); 25 | echo json_encode($callback); 26 | }elseif($this->model->userIsExist('username',$username)){ 27 | $callback=array( 28 | 'status'=>false, 29 | 'msg'=>'用户名重复,请输入其他用户名吧' 30 | ); 31 | echo json_encode($callback); 32 | }elseif(strlen($email)>100||$email==''||!is_email($email)){ 33 | $callback=array( 34 | 'status'=>false, 35 | 'msg'=>'请重新输入邮箱' 36 | ); 37 | echo json_encode($callback); 38 | }elseif($this->model->userIsExist('email',$email)){ 39 | $callback=array( 40 | 'status'=>false, 41 | 'msg'=>'邮箱重复,请输入其他邮箱吧' 42 | ); 43 | echo json_encode($callback); 44 | }elseif(strlen($pwd)>30||$pwd==''){ 45 | $callback=array( 46 | 'status'=>false, 47 | 'msg'=>'请重新输入密码' 48 | ); 49 | echo json_encode($callback); 50 | }elseif($this->config['show_register_captcha']&&!$securimage->check(strtolower($captcha))){ 51 | $callback=array( 52 | 'status'=>false, 53 | 'refresh_captcha'=>true, 54 | 'msg'=>'请重新输入验证码' 55 | ); 56 | echo json_encode($callback); 57 | }else{ 58 | $uid=$this->model->addUser($username,$email,$pwd); 59 | if($uid>0){ 60 | $callback=array( 61 | 'status'=>true, 62 | 'url'=>url('profile/avatar') 63 | ); 64 | //send msg to new user(optional) 65 | $admin_username=$this->model('user')->getUsernameByUid(1); 66 | $msg_content=$username.'您好,欢迎来到爱码士,爱码士只为极客和爱代码的人们,这里我们聊极客、聊代码、聊生活、聊职场,为打造一种热闹亲和的盖楼氛围,爱码士设计了一种新颖的论坛界面。请保持友好互助的心态和极客们交流'; 67 | if($uid>1){ 68 | $msg_model=$this->model('msg'); 69 | $msg_model->addmsg(1,$admin_username,$uid,$msg_content); 70 | $msg_model->msgDel(1,$msg_model->msg_prefix.'1_'.$uid); 71 | } 72 | $auth=encrypt("$uid\t$username"); 73 | if($_POST['remember']==0){ 74 | setcookie($this->config['cookie_prefix'].'Auth',$auth,0,'/'); 75 | }else{ 76 | setcookie($this->config['cookie_prefix'].'Auth',$auth,time()+5616000,'/'); 77 | } 78 | echo json_encode($callback); 79 | }else{ 80 | $callback=array( 81 | 'status'=>false, 82 | 'msg'=>'网络繁忙,请稍后重试' 83 | ); 84 | echo json_encode($callback); 85 | } 86 | } 87 | } 88 | public function loginProcess(){ 89 | session_start(); 90 | isint($this->uid)&&exit;//if user has signed in 91 | include_once ROOT_DIR.'application'.DIRECTORY_SEPARATOR.'securimage'.DIRECTORY_SEPARATOR.'securimage.php'; 92 | $securimage = new Securimage();//for captcha 93 | $login_email=x($_POST['login_email']); 94 | $login_pwd=x($_POST['login_pwd']); 95 | $captcha=x($_POST['login_captcha']); 96 | if(!is_email($login_email)){ 97 | $callback=array( 98 | 'status'=>false, 99 | 'msg'=>'请输入正确的邮箱' 100 | ); 101 | echo json_encode($callback); 102 | }else if($login_pwd==''){ 103 | $callback=array( 104 | 'status'=>false, 105 | 'msg'=>'请输入正确的密码' 106 | ); 107 | echo json_encode($callback); 108 | }elseif($this->config['show_login_captcha']&&!$securimage->check(strtolower($captcha))){ 109 | $callback=array( 110 | 'status'=>false, 111 | 'refresh_captcha'=>true, 112 | 'msg'=>'请重新输入验证码' 113 | ); 114 | echo json_encode($callback); 115 | }else{ 116 | $user=$this->model->checkUser($login_email,$login_pwd); 117 | if(!is_array($user)){ 118 | $callback=array( 119 | 'status'=>false, 120 | 'msg'=>'邮箱或密码错误,请重新登录' 121 | ); 122 | echo json_encode($callback); 123 | }else{ 124 | $callback=array( 125 | 'status'=>true 126 | ); 127 | $uid=$user['uid']; 128 | $username=$user['username']; 129 | $auth=encrypt($uid); 130 | if(intval($_POST['remember'])==0){ 131 | setcookie($this->config['cookie_prefix'].'Auth',$auth,0,'/'); 132 | setcookie($this->config['cookie_prefix'].'username',$username,0,'/'); 133 | }else{ 134 | setcookie($this->config['cookie_prefix'].'Auth',$auth,time()+5616000,'/'); 135 | setcookie($this->config['cookie_prefix'].'username',$username,time()+5616000,'/'); 136 | } 137 | echo json_encode($callback); 138 | } 139 | } 140 | } 141 | public function logout(){ 142 | setcookie($this->config['cookie_prefix'].'Auth','',time()-1,'/'); 143 | setcookie($this->config['cookie_prefix'].'avatar_small','',time()-1,'/'); 144 | setcookie($this->config['cookie_prefix'].'avatar_big','',time()-1,'/'); 145 | setcookie($this->config['cookie_prefix'].'user_info','',time()-1,'/'); 146 | setcookie($this->config['cookie_prefix'].'username','',time()-1,'/'); 147 | header('location:'.$this->config['site']); 148 | } 149 | } 150 | ?> 151 | -------------------------------------------------------------------------------- /application/views/default/user_notifications.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 47 |
    48 |
    49 | 0):?> 50 | 清除所有通知信息 51 | $v): ?> 52 |
    53 |
    54 | " title="此消息已读">• 55 | 56 | 57 | 58 | 59 | : 60 | 61 |
    62 | 63 | 64 |
    65 |
    66 |
    67 |
    68 | 69 |
    70 | 回复您: 71 | 72 |
    73 | 74 |
    75 |
    76 | 您对帖子的回复: 77 | 78 |
    79 |
    80 | 81 |
    82 | 83 |
    84 |
    85 | 86 | 87 | 88 | 89 | 90 | 91 |
    92 |
    93 |
    94 | 95 |
    96 |
    97 |
    98 | 浏览() 99 | 回复() 100 | 投票() 101 | 收藏() 102 | 发表于 103 |
    104 |
    105 |
    106 |
    107 |
    108 | 113 |
    114 |
    115 | 暂无新通知 116 |
    117 | 118 |
    119 |
    120 | -------------------------------------------------------------------------------- /application/thumb/PhpThumb.inc.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @filesource 23 | */ 24 | 25 | 26 | 27 | /** 28 | * PhpThumb Object 29 | * 30 | * This singleton object is essentially a function library that helps with core validation 31 | * and loading of the core classes and plugins. There isn't really any need to access it directly, 32 | * unless you're developing a plugin and need to take advantage of any of the functionality contained 33 | * within. 34 | * 35 | * If you're not familiar with singleton patterns, here's how you get an instance of this class (since you 36 | * can't create one via the new keyword): 37 | * $pt = PhpThumb::getInstance(); 38 | * 39 | * It's that simple! Outside of that, there's no need to modify anything within this class, unless you're doing 40 | * some crazy customization... then knock yourself out! :) 41 | * 42 | * @package PhpThumb 43 | * @subpackage Core 44 | */ 45 | class PhpThumb 46 | { 47 | /** 48 | * Instance of self 49 | * 50 | * @var object PhpThumb 51 | */ 52 | protected static $_instance; 53 | /** 54 | * The plugin registry 55 | * 56 | * This is where all plugins to be loaded are stored. Data about the plugin is 57 | * provided, and currently consists of: 58 | * - loaded: true/false 59 | * - implementation: gd/imagick/both 60 | * 61 | * @var array 62 | */ 63 | protected $_registry; 64 | /** 65 | * What implementations are available 66 | * 67 | * This stores what implementations are available based on the loaded 68 | * extensions in PHP, NOT whether or not the class files are present. 69 | * 70 | * @var array 71 | */ 72 | protected $_implementations; 73 | 74 | /** 75 | * Returns an instance of self 76 | * 77 | * This is the usual singleton function that returns / instantiates the object 78 | * 79 | * @return PhpThumb 80 | */ 81 | public static function getInstance () 82 | { 83 | if(!(self::$_instance instanceof self)) 84 | { 85 | self::$_instance = new self(); 86 | } 87 | 88 | return self::$_instance; 89 | } 90 | 91 | /** 92 | * Class constructor 93 | * 94 | * Initializes all the variables, and does some preliminary validation / checking of stuff 95 | * 96 | */ 97 | private function __construct () 98 | { 99 | $this->_registry = array(); 100 | $this->_implementations = array('gd' => false, 'imagick' => false); 101 | 102 | $this->getImplementations(); 103 | } 104 | 105 | /** 106 | * Finds out what implementations are available 107 | * 108 | * This function loops over $this->_implementations and validates that the required extensions are loaded. 109 | * 110 | * I had planned on attempting to load them dynamically via dl(), but that would provide more overhead than I 111 | * was comfortable with (and would probably fail 99% of the time anyway) 112 | * 113 | */ 114 | private function getImplementations () 115 | { 116 | foreach($this->_implementations as $extension => $loaded) 117 | { 118 | if($loaded) 119 | { 120 | continue; 121 | } 122 | 123 | if(extension_loaded($extension)) 124 | { 125 | $this->_implementations[$extension] = true; 126 | } 127 | } 128 | } 129 | 130 | /** 131 | * Returns whether or not $implementation is valid (available) 132 | * 133 | * If 'all' is passed, true is only returned if ALL implementations are available. 134 | * 135 | * You can also pass 'n/a', which always returns true 136 | * 137 | * @return bool 138 | * @param string $implementation 139 | */ 140 | public function isValidImplementation ($implementation) 141 | { 142 | if ($implementation == 'n/a') 143 | { 144 | return true; 145 | } 146 | 147 | if ($implementation == 'all') 148 | { 149 | foreach ($this->_implementations as $imp => $value) 150 | { 151 | if ($value == false) 152 | { 153 | return false; 154 | } 155 | } 156 | 157 | return true; 158 | } 159 | 160 | if (array_key_exists($implementation, $this->_implementations)) 161 | { 162 | return $this->_implementations[$implementation]; 163 | } 164 | 165 | return false; 166 | } 167 | 168 | /** 169 | * Registers a plugin in the registry 170 | * 171 | * Adds a plugin to the registry if it isn't already loaded, and if the provided 172 | * implementation is valid. Note that you can pass the following special keywords 173 | * for implementation: 174 | * - all - Requires that all implementations be available 175 | * - n/a - Doesn't require any implementation 176 | * 177 | * When a plugin is added to the registry, it's added as a key on $this->_registry with the value 178 | * being an array containing the following keys: 179 | * - loaded - whether or not the plugin has been "loaded" into the core class 180 | * - implementation - what implementation this plugin is valid for 181 | * 182 | * @return bool 183 | * @param string $pluginName 184 | * @param string $implementation 185 | */ 186 | public function registerPlugin ($pluginName, $implementation) 187 | { 188 | if (!array_key_exists($pluginName, $this->_registry) && $this->isValidImplementation($implementation)) 189 | { 190 | $this->_registry[$pluginName] = array('loaded' => false, 'implementation' => $implementation); 191 | return true; 192 | } 193 | 194 | return false; 195 | } 196 | 197 | /** 198 | * Loads all the plugins in $pluginPath 199 | * 200 | * All this function does is include all files inside the $pluginPath directory. The plugins themselves 201 | * will not be added to the registry unless you've properly added the code to do so inside your plugin file. 202 | * 203 | * @param string $pluginPath 204 | */ 205 | public function loadPlugins ($pluginPath) 206 | { 207 | // strip the trailing slash if present 208 | if (substr($pluginPath, strlen($pluginPath) - 1, 1) == '/') 209 | { 210 | $pluginPath = substr($pluginPath, 0, strlen($pluginPath) - 1); 211 | } 212 | 213 | if ($handle = opendir($pluginPath)) 214 | { 215 | while (false !== ($file = readdir($handle))) 216 | { 217 | if ($file == '.' || $file == '..' || $file == '.svn') 218 | { 219 | continue; 220 | } 221 | 222 | include_once($pluginPath . '/' . $file); 223 | } 224 | } 225 | } 226 | 227 | /** 228 | * Returns the plugin registry for the supplied implementation 229 | * 230 | * @return array 231 | * @param string $implementation 232 | */ 233 | public function getPluginRegistry ($implementation) 234 | { 235 | $returnArray = array(); 236 | 237 | foreach ($this->_registry as $plugin => $meta) 238 | { 239 | if ($meta['implementation'] == 'n/a' || $meta['implementation'] == $implementation) 240 | { 241 | $returnArray[$plugin] = $meta; 242 | } 243 | } 244 | 245 | return $returnArray; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /public/zepto.timeago.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | // AMD. Register as an anonymous module. 4 | define(['zepto'], factory); 5 | } else if (typeof module === 'object' && typeof module.exports === 'object') { 6 | factory(require('zepto')); 7 | } else { 8 | // Browser globals 9 | factory(Zepto); 10 | } 11 | }(function ($) { 12 | $.timeago = function(timestamp) { 13 | if (timestamp instanceof Date) { 14 | return inWords(timestamp); 15 | } else if (typeof timestamp === "string") { 16 | return inWords($.timeago.parse(timestamp)); 17 | } else if (typeof timestamp === "number") { 18 | return inWords(new Date(timestamp)); 19 | } else { 20 | return inWords($.timeago.datetime(timestamp)); 21 | } 22 | }; 23 | var $t = $.timeago; 24 | 25 | $.extend($.timeago, { 26 | settings: { 27 | refreshMillis: 60000, 28 | allowPast: true, 29 | allowFuture: false, 30 | localeTitle: false, 31 | cutoff: 0, 32 | strings: { 33 | prefixAgo: null, 34 | prefixFromNow: null, 35 | suffixAgo: "前", 36 | suffixFromNow: "当前", 37 | inPast: '过去', 38 | seconds: "%d秒", 39 | minute: "1分钟", 40 | minutes: "%d分钟", 41 | hour: "1小时前", 42 | hours: "%d小时", 43 | day: "1天", 44 | days: "%d天", 45 | month: "1个月", 46 | months: "%d个月", 47 | year: "1年", 48 | years: "%d年", 49 | wordSeparator: "", 50 | numbers: [] 51 | } 52 | }, 53 | 54 | inWords: function(distanceMillis) { 55 | if(!this.settings.allowPast && ! this.settings.allowFuture) { 56 | throw 'timeago allowPast and allowFuture settings can not both be set to false.'; 57 | } 58 | 59 | var $l = this.settings.strings; 60 | var prefix = $l.prefixAgo; 61 | var suffix = $l.suffixAgo; 62 | if (this.settings.allowFuture) { 63 | if (distanceMillis < 0) { 64 | prefix = $l.prefixFromNow; 65 | suffix = $l.suffixFromNow; 66 | } 67 | } 68 | 69 | if(!this.settings.allowPast && distanceMillis >= 0) { 70 | return this.settings.strings.inPast; 71 | } 72 | 73 | var seconds = Math.abs(distanceMillis) / 1000; 74 | var minutes = seconds / 60; 75 | var hours = minutes / 60; 76 | var days = hours / 24; 77 | var years = days / 365; 78 | 79 | function substitute(stringOrFunction, number) { 80 | var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; 81 | var value = ($l.numbers && $l.numbers[number]) || number; 82 | return string.replace(/%d/i, value); 83 | } 84 | 85 | var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || 86 | seconds < 90 && substitute($l.minute, 1) || 87 | minutes < 45 && substitute($l.minutes, Math.round(minutes)) || 88 | minutes < 90 && substitute($l.hour, 1) || 89 | hours < 24 && substitute($l.hours, Math.round(hours)) || 90 | hours < 42 && substitute($l.day, 1) || 91 | days < 30 && substitute($l.days, Math.round(days)) || 92 | days < 45 && substitute($l.month, 1) || 93 | days < 365 && substitute($l.months, Math.round(days / 30)) || 94 | years < 1.5 && substitute($l.year, 1) || 95 | substitute($l.years, Math.round(years)); 96 | 97 | var separator = $l.wordSeparator || ""; 98 | if ($l.wordSeparator === undefined) { separator = " "; } 99 | return $.trim([prefix, words, suffix].join(separator)); 100 | }, 101 | 102 | parse: function(iso8601) { 103 | var s = $.trim(iso8601); 104 | s = s.replace(/\.\d+/,""); // remove milliseconds 105 | s = s.replace(/-/,"/").replace(/-/,"/"); 106 | s = s.replace(/T/," ").replace(/Z/," UTC"); 107 | s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 108 | s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900 109 | return new Date(s); 110 | }, 111 | datetime: function(elem) { 112 | var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title"); 113 | return $t.parse(iso8601); 114 | }, 115 | isTime: function(elem) { 116 | // jQuery's `is()` doesn't play well with HTML5 in IE 117 | return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time"); 118 | } 119 | }); 120 | 121 | // functions that can be called via $(el).timeago('action') 122 | // init is default when no action is given 123 | // functions are called with context of a single element 124 | var functions = { 125 | init: function(){ 126 | var refresh_el = $.proxy(refresh, this); 127 | refresh_el(); 128 | var $s = $t.settings; 129 | if ($s.refreshMillis > 0) { 130 | this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis); 131 | } 132 | }, 133 | update: function(time){ 134 | var parsedTime = $t.parse(time); 135 | $(this).data('timeago', { datetime: parsedTime }); 136 | if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString()); 137 | refresh.apply(this); 138 | }, 139 | updateFromDOM: function(){ 140 | $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) }); 141 | refresh.apply(this); 142 | }, 143 | dispose: function () { 144 | if (this._timeagoInterval) { 145 | window.clearInterval(this._timeagoInterval); 146 | this._timeagoInterval = null; 147 | } 148 | } 149 | }; 150 | 151 | $.fn.timeago = function(action, options) { 152 | var fn = action ? functions[action] : functions.init; 153 | if(!fn){ 154 | throw new Error("Unknown function name '"+ action +"' for timeago"); 155 | } 156 | // each over objects here and call the requested function 157 | this.each(function(){ 158 | fn.call(this, options); 159 | }); 160 | return this; 161 | }; 162 | 163 | function refresh() { 164 | //check if it's still visible 165 | if(!$.contains(document.documentElement,this)){ 166 | //stop if it has been removed 167 | $(this).timeago("dispose"); 168 | return this; 169 | } 170 | 171 | var data = prepareData(this); 172 | var $s = $t.settings; 173 | 174 | if (!isNaN(data.datetime)) { 175 | if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) { 176 | $(this).text(inWords(data.datetime)); 177 | } 178 | } 179 | return this; 180 | } 181 | 182 | function prepareData(element) { 183 | element = $(element); 184 | if (!element.data("timeago")) { 185 | element.data("timeago", { datetime: $t.datetime(element) }); 186 | var text = $.trim(element.text()); 187 | if ($t.settings.localeTitle) { 188 | element.attr("title", element.data('timeago').datetime.toLocaleString()); 189 | } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) { 190 | element.attr("title", text); 191 | } 192 | } 193 | return element.data("timeago"); 194 | } 195 | 196 | function inWords(date) { 197 | return $t.inWords(distance(date)); 198 | } 199 | 200 | function distance(date) { 201 | return (new Date().getTime() - date.getTime()); 202 | } 203 | 204 | // fix for IE6 suckage 205 | document.createElement("abbr"); 206 | document.createElement("time"); 207 | })); -------------------------------------------------------------------------------- /public/cropbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by ezgoing on 14/9/2014. 3 | */ 4 | 5 | "use strict"; 6 | (function (factory) { 7 | if (typeof define === 'function' && define.amd) { 8 | define(['jquery'], factory); 9 | } else { 10 | factory(jQuery); 11 | } 12 | }(function ($) { 13 | var cropbox = function(options, el){ 14 | var el = el || $(options.imageBox), 15 | obj = 16 | { 17 | state : {}, 18 | ratio : 1, 19 | options : options, 20 | imageBox : el, 21 | thumbBox : el.find(options.thumbBox), 22 | spinner : el.find(options.spinner), 23 | image : new Image(), 24 | getDataURL: function () 25 | { 26 | var width = this.thumbBox.width(), 27 | height = this.thumbBox.height(), 28 | canvas = document.createElement("canvas"), 29 | dim = el.css('background-position').split(' '), 30 | size = el.css('background-size').split(' '), 31 | dx = parseInt(dim[0]) - el.width()/2 + width/2, 32 | dy = parseInt(dim[1]) - el.height()/2 + height/2, 33 | dw = parseInt(size[0]), 34 | dh = parseInt(size[1]), 35 | sh = parseInt(this.image.height), 36 | sw = parseInt(this.image.width); 37 | 38 | canvas.width = width; 39 | canvas.height = height; 40 | var context = canvas.getContext("2d"); 41 | context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh); 42 | var imageData = canvas.toDataURL('image/png'); 43 | return imageData; 44 | }, 45 | getBlob: function() 46 | { 47 | var imageData = this.getDataURL(); 48 | var b64 = imageData.replace('data:image/png;base64,',''); 49 | var binary = atob(b64); 50 | var array = []; 51 | for (var i = 0; i < binary.length; i++) { 52 | array.push(binary.charCodeAt(i)); 53 | } 54 | return new Blob([new Uint8Array(array)], {type: 'image/png'}); 55 | }, 56 | zoomIn: function () 57 | { 58 | this.ratio*=1.1; 59 | setBackground(); 60 | }, 61 | zoomOut: function () 62 | { 63 | this.ratio*=0.9; 64 | setBackground(); 65 | } 66 | }, 67 | setBackground = function() 68 | { 69 | var w = parseInt(obj.image.width)*obj.ratio; 70 | var h = parseInt(obj.image.height)*obj.ratio; 71 | 72 | var pw = (el.width() - w) / 2; 73 | var ph = (el.height() - h) / 2; 74 | 75 | el.css({ 76 | 'background-image': 'url(' + obj.image.src + ')', 77 | 'background-size': w +'px ' + h + 'px', 78 | 'background-position': pw + 'px ' + ph + 'px', 79 | 'background-repeat': 'no-repeat'}); 80 | }, 81 | imgMouseDown = function(e) 82 | { 83 | e.stopImmediatePropagation(); 84 | 85 | obj.state.dragable = true; 86 | obj.state.mouseX = e.clientX; 87 | obj.state.mouseY = e.clientY; 88 | }, 89 | imgMouseMove = function(e) 90 | { 91 | e.stopImmediatePropagation(); 92 | 93 | if (obj.state.dragable) 94 | { 95 | var x = e.clientX - obj.state.mouseX; 96 | var y = e.clientY - obj.state.mouseY; 97 | 98 | var bg = el.css('background-position').split(' '); 99 | 100 | var bgX = x + parseInt(bg[0]); 101 | var bgY = y + parseInt(bg[1]); 102 | 103 | el.css('background-position', bgX +'px ' + bgY + 'px'); 104 | 105 | obj.state.mouseX = e.clientX; 106 | obj.state.mouseY = e.clientY; 107 | } 108 | }, 109 | imgMouseUp = function(e) 110 | { 111 | e.stopImmediatePropagation(); 112 | obj.state.dragable = false; 113 | }, 114 | zoomImage = function(e) 115 | { 116 | e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0 ? obj.ratio*=1.1 : obj.ratio*=0.9; 117 | setBackground(); 118 | } 119 | 120 | obj.spinner.show(); 121 | obj.image.onload = function() { 122 | obj.spinner.hide(); 123 | setBackground(); 124 | 125 | el.bind('mousedown', imgMouseDown); 126 | el.bind('mousemove', imgMouseMove); 127 | $(window).bind('mouseup', imgMouseUp); 128 | el.bind('mousewheel DOMMouseScroll', zoomImage); 129 | }; 130 | obj.image.src = options.imgSrc; 131 | el.on('remove', function(){$(window).unbind('mouseup', imgMouseUp)}); 132 | 133 | return obj; 134 | }; 135 | 136 | jQuery.fn.cropbox = function(options){ 137 | return new cropbox(options, this); 138 | }; 139 | })); 140 | $(window).load(function() { 141 | var options = 142 | { 143 | thumbBox: '.thumbBox', 144 | spinner: '.spinner', 145 | imgSrc: '' 146 | } 147 | var cropper; 148 | $('#html5_upload').on('change', function(){ 149 | var reader = new FileReader(); 150 | $('#avatar_pre').hide(); 151 | $('#avatar_select').removeClass('none'); 152 | reader.onload = function(e) { 153 | options.imgSrc = e.target.result; 154 | cropper = $('.imageBox').cropbox(options); 155 | } 156 | reader.readAsDataURL(this.files[0]); 157 | this.files = []; 158 | }) 159 | $('#crop_btn').click(function(){ 160 | var _t=$(this); 161 | if(_t.hasClass('disabled')){ 162 | return false; 163 | } 164 | _t.addClass('disabled'); 165 | ZENG.msgbox.show('正在上传头像,请等待...', 6, 4800000); 166 | $.post(U('profile/doAvatar'),{content:cropper.getDataURL()},function(d){ 167 | if(d.status){ 168 | ZENG.msgbox.show('图片上传成功', 4, 2000); 169 | delCookie(cookie_prefix+'avatar_big','/'); 170 | delCookie(cookie_prefix+'avatar_small','/'); 171 | setTimeout("location.reload()",2000); 172 | }else{ 173 | ZENG.msgbox.show(d.msg,3, 2000); 174 | } 175 | _t.removeClass('disabled'); 176 | },'json'); 177 | }); 178 | //detectFlash()?$('#avatar_preupload').remove():$('#flash_container').remove(); 179 | }); 180 | function detectFlash() { 181 | if(navigator.mimeTypes.length>0){ 182 | var flashAct = navigator.mimeTypes["application/x-shockwave-flash"]; 183 | return flashAct != null ? flashAct.enabledPlugin!=null : false; 184 | } else if(self.ActiveXObject) { 185 | try { 186 | new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); 187 | return true; 188 | } catch (oError) { 189 | return false; 190 | } 191 | } 192 | } -------------------------------------------------------------------------------- /public/css/icon.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'icomoon'; 3 | src:url('../fonts/icomoon.eot?npzd73'); 4 | src:url('../fonts/icomoon.eot?#iefixnpzd73') format('embedded-opentype'), 5 | url('../fonts/icomoon.woff?npzd73') format('woff'), 6 | url('../fonts/icomoon.ttf?npzd73') format('truetype'), 7 | url('../fonts/icomoon.svg?npzd73#icomoon') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | [class^="icon-"], [class*=" icon-"] { 13 | font-family: 'icomoon'; 14 | speak: none; 15 | font-style: normal; 16 | font-weight: normal; 17 | font-variant: normal; 18 | text-transform: none; 19 | line-height: 1; 20 | 21 | /* Better Font Rendering =========== */ 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | } 25 | 26 | .icon-activity:before { 27 | content: "\e66b"; 28 | } 29 | 30 | .icon-wegene:before { 31 | content: "\e667"; 32 | } 33 | 34 | .icon-contact:before { 35 | content: "\e668"; 36 | } 37 | 38 | .icon-about:before { 39 | content: "\e669"; 40 | } 41 | 42 | .icon-protect:before { 43 | content: "\e66a"; 44 | } 45 | 46 | .icon-drug:before { 47 | content: "\e666"; 48 | } 49 | 50 | .icon-hear:before { 51 | content: "\e663"; 52 | } 53 | 54 | .icon-ear:before { 55 | content: "\e664"; 56 | } 57 | 58 | .icon-beat:before { 59 | content: "\e665"; 60 | } 61 | 62 | .icon-23:before { 63 | content: "\e662"; 64 | } 65 | 66 | .icon-good:before { 67 | content: "\e660"; 68 | } 69 | 70 | .icon-bad:before { 71 | content: "\e661"; 72 | } 73 | 74 | .icon-format:before { 75 | content: "\e65f"; 76 | } 77 | 78 | .icon-strike:before { 79 | content: "\e65e"; 80 | } 81 | 82 | .icon-full:before { 83 | content: "\e65d"; 84 | } 85 | 86 | .icon-gene:before { 87 | content: "\e600"; 88 | } 89 | 90 | .icon-count:before { 91 | content: "\e65a"; 92 | } 93 | 94 | .icon-order:before { 95 | content: "\e65b"; 96 | } 97 | 98 | .icon-google:before { 99 | content: "\e657"; 100 | } 101 | 102 | .icon-facebook:before { 103 | content: "\e658"; 104 | } 105 | 106 | .icon-twitter:before { 107 | content: "\e659"; 108 | } 109 | 110 | .icon-cart:before { 111 | content: "\e656"; 112 | } 113 | 114 | .icon-bulb:before { 115 | content: "\e655"; 116 | } 117 | 118 | .icon-download:before { 119 | content: "\e654"; 120 | } 121 | 122 | .icon-home:before { 123 | content: "\e601"; 124 | } 125 | 126 | .icon-bar:before { 127 | content: "\e653"; 128 | } 129 | 130 | .icon-right:before { 131 | content: "\e651"; 132 | } 133 | 134 | .icon-left:before { 135 | content: "\e652"; 136 | } 137 | 138 | .icon-unlock:before { 139 | content: "\e650"; 140 | } 141 | 142 | .icon-verify:before { 143 | content: "\e64a"; 144 | } 145 | 146 | .icon-date:before { 147 | content: "\e64b"; 148 | } 149 | 150 | .icon-log:before { 151 | content: "\e64c"; 152 | } 153 | 154 | .icon-forbid:before { 155 | content: "\e64d"; 156 | } 157 | 158 | .icon-transfer:before { 159 | content: "\e64e"; 160 | } 161 | 162 | .icon-reader:before { 163 | content: "\e64f"; 164 | } 165 | 166 | .icon-phone:before { 167 | content: "\e648"; 168 | } 169 | 170 | .icon-file:before { 171 | content: "\e649"; 172 | } 173 | 174 | .icon-ol:before { 175 | content: "\e63e"; 176 | } 177 | 178 | .icon-undo:before { 179 | content: "\e646"; 180 | } 181 | 182 | .icon-redo:before { 183 | content: "\e647"; 184 | } 185 | 186 | .icon-bold:before { 187 | content: "\e63a"; 188 | } 189 | 190 | .icon-italic:before { 191 | content: "\e63b"; 192 | } 193 | 194 | .icon-underline:before { 195 | content: "\e63c"; 196 | } 197 | 198 | .icon-ul:before { 199 | content: "\e63d"; 200 | } 201 | 202 | .icon-image:before { 203 | content: "\e63f"; 204 | } 205 | 206 | .icon-video:before { 207 | content: "\e640"; 208 | } 209 | 210 | .icon-quote:before { 211 | content: "\e641"; 212 | } 213 | 214 | .icon-code:before { 215 | content: "\e642"; 216 | } 217 | 218 | .icon-preview:before { 219 | content: "\e643"; 220 | } 221 | 222 | .icon-help:before { 223 | content: "\e644"; 224 | } 225 | 226 | .icon-h:before { 227 | content: "\e645"; 228 | } 229 | 230 | .icon-prestige:before { 231 | content: "\e638"; 232 | } 233 | 234 | .icon-v:before { 235 | content: "\e639"; 236 | } 237 | 238 | .icon-score:before { 239 | content: "\e637"; 240 | } 241 | 242 | .icon-plus:before { 243 | content: "\e635"; 244 | } 245 | 246 | .icon-followed:before { 247 | content: "\e636"; 248 | } 249 | 250 | .icon-mytopic:before { 251 | content: "\e633"; 252 | } 253 | 254 | .icon-up:before { 255 | content: "\e634"; 256 | } 257 | 258 | .icon-trash:before { 259 | content: "\e632"; 260 | } 261 | 262 | .icon-fold:before { 263 | content: "\e62c"; 264 | } 265 | 266 | .icon-thank:before { 267 | content: "\e62d"; 268 | } 269 | 270 | .icon-report:before { 271 | content: "\e62e"; 272 | } 273 | 274 | .icon-qzone:before { 275 | content: "\e62f"; 276 | } 277 | 278 | .icon-at:before { 279 | content: "\e630"; 280 | } 281 | 282 | .icon-attach:before { 283 | content: "\e631"; 284 | } 285 | 286 | .icon-bell:before { 287 | content: "\e62b"; 288 | } 289 | 290 | .icon-triangle:before { 291 | content: "\e62a"; 292 | } 293 | 294 | .icon-wechat:before { 295 | content: "\e628"; 296 | } 297 | 298 | .icon-lock:before { 299 | content: "\e629"; 300 | } 301 | 302 | .icon-i:before { 303 | content: "\e626"; 304 | } 305 | 306 | .icon-bubble:before { 307 | content: "\e627"; 308 | } 309 | 310 | .icon-flag:before { 311 | content: "\e625"; 312 | } 313 | 314 | .icon-txweibo:before { 315 | content: "\e622"; 316 | } 317 | 318 | .icon-bestbg:before { 319 | content: "\e623"; 320 | } 321 | 322 | .icon-best:before { 323 | content: "\e624"; 324 | } 325 | 326 | .icon-job:before { 327 | content: "\e61e"; 328 | } 329 | 330 | .icon-favor:before { 331 | content: "\e620"; 332 | } 333 | 334 | .icon-down:before { 335 | content: "\e621"; 336 | } 337 | 338 | .icon-location:before { 339 | content: "\e61d"; 340 | } 341 | 342 | .icon-bind:before { 343 | content: "\e61f"; 344 | } 345 | 346 | .icon-weibo:before { 347 | content: "\e618"; 348 | } 349 | 350 | .icon-qq:before { 351 | content: "\e619"; 352 | } 353 | 354 | .icon-signup:before { 355 | content: "\e61a"; 356 | } 357 | 358 | .icon-users:before { 359 | content: "\e61b"; 360 | } 361 | 362 | .icon-topic:before { 363 | content: "\e61c"; 364 | } 365 | 366 | .icon-login:before { 367 | content: "\e617"; 368 | } 369 | 370 | .icon-logout:before { 371 | content: "\e616"; 372 | } 373 | 374 | .icon-insert:before { 375 | content: "\e612"; 376 | } 377 | 378 | .icon-setting:before { 379 | content: "\e615"; 380 | } 381 | 382 | .icon-inbox:before { 383 | content: "\e614"; 384 | } 385 | 386 | .icon-pic:before { 387 | content: "\e610"; 388 | } 389 | 390 | .icon-user:before { 391 | content: "\e613"; 392 | } 393 | 394 | .icon-delete:before { 395 | content: "\e611"; 396 | } 397 | 398 | .icon-comment:before { 399 | content: "\e60f"; 400 | } 401 | 402 | .icon-share:before { 403 | content: "\e60e"; 404 | } 405 | 406 | .icon-loading:before { 407 | content: "\e60d"; 408 | } 409 | 410 | .icon-inviteask:before { 411 | content: "\e60c"; 412 | } 413 | 414 | .icon-list:before { 415 | content: "\e602"; 416 | } 417 | 418 | .icon-ask:before { 419 | content: "\e603"; 420 | } 421 | 422 | .icon-search:before { 423 | content: "\e604"; 424 | } 425 | 426 | .icon-more:before { 427 | content: "\e605"; 428 | } 429 | 430 | .icon-agree:before { 431 | content: "\e606"; 432 | } 433 | 434 | .icon-disagree:before { 435 | content: "\e607"; 436 | } 437 | 438 | .icon-reply:before { 439 | content: "\e608"; 440 | } 441 | 442 | .icon-draft:before { 443 | content: "\e609"; 444 | } 445 | 446 | .icon-check:before { 447 | content: "\e60a"; 448 | } 449 | 450 | .icon-invite:before { 451 | content: "\e60b"; 452 | } 453 | 454 | .icon-edit:before { 455 | content: "\e65c"; 456 | } 457 | 458 | -------------------------------------------------------------------------------- /public/jquery.timeago.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Timeago is a jQuery plugin that makes it easy to support automatically 3 | * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). 4 | * 5 | * @name timeago 6 | * @version 1.4.3 7 | * @requires jQuery v1.2.3+ 8 | * @author Ryan McGeary 9 | * @license MIT License - http://www.opensource.org/licenses/mit-license.php 10 | * 11 | * For usage and examples, visit: 12 | * http://timeago.yarp.com/ 13 | * 14 | * Copyright (c) 2008-2015, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) 15 | */ 16 | 17 | (function (factory) { 18 | if (typeof define === 'function' && define.amd) { 19 | // AMD. Register as an anonymous module. 20 | define(['jquery'], factory); 21 | } else if (typeof module === 'object' && typeof module.exports === 'object') { 22 | factory(require('jquery')); 23 | } else { 24 | // Browser globals 25 | factory(jQuery); 26 | } 27 | }(function ($) { 28 | $.timeago = function(timestamp) { 29 | if (timestamp instanceof Date) { 30 | return inWords(timestamp); 31 | } else if (typeof timestamp === "string") { 32 | return inWords($.timeago.parse(timestamp)); 33 | } else if (typeof timestamp === "number") { 34 | return inWords(new Date(timestamp)); 35 | } else { 36 | return inWords($.timeago.datetime(timestamp)); 37 | } 38 | }; 39 | var $t = $.timeago; 40 | 41 | $.extend($.timeago, { 42 | settings: { 43 | refreshMillis: 60000, 44 | allowPast: true, 45 | allowFuture: false, 46 | localeTitle: false, 47 | cutoff: 0, 48 | strings: { 49 | prefixAgo: null, 50 | prefixFromNow: null, 51 | suffixAgo: "前", 52 | suffixFromNow: "当前", 53 | inPast: '过去', 54 | seconds: "%d秒", 55 | minute: "1分钟", 56 | minutes: "%d分钟", 57 | hour: "1小时前", 58 | hours: "%d小时", 59 | day: "1天", 60 | days: "%d天", 61 | month: "1个月", 62 | months: "%d个月", 63 | year: "1年", 64 | years: "%d年", 65 | wordSeparator: "", 66 | numbers: [] 67 | } 68 | }, 69 | 70 | inWords: function(distanceMillis) { 71 | if(!this.settings.allowPast && ! this.settings.allowFuture) { 72 | throw 'timeago allowPast and allowFuture settings can not both be set to false.'; 73 | } 74 | 75 | var $l = this.settings.strings; 76 | var prefix = $l.prefixAgo; 77 | var suffix = $l.suffixAgo; 78 | if (this.settings.allowFuture) { 79 | if (distanceMillis < 0) { 80 | prefix = $l.prefixFromNow; 81 | suffix = $l.suffixFromNow; 82 | } 83 | } 84 | 85 | if(!this.settings.allowPast && distanceMillis >= 0) { 86 | return this.settings.strings.inPast; 87 | } 88 | 89 | var seconds = Math.abs(distanceMillis) / 1000; 90 | var minutes = seconds / 60; 91 | var hours = minutes / 60; 92 | var days = hours / 24; 93 | var years = days / 365; 94 | 95 | function substitute(stringOrFunction, number) { 96 | var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; 97 | var value = ($l.numbers && $l.numbers[number]) || number; 98 | return string.replace(/%d/i, value); 99 | } 100 | 101 | var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || 102 | seconds < 90 && substitute($l.minute, 1) || 103 | minutes < 45 && substitute($l.minutes, Math.round(minutes)) || 104 | minutes < 90 && substitute($l.hour, 1) || 105 | hours < 24 && substitute($l.hours, Math.round(hours)) || 106 | hours < 42 && substitute($l.day, 1) || 107 | days < 30 && substitute($l.days, Math.round(days)) || 108 | days < 45 && substitute($l.month, 1) || 109 | days < 365 && substitute($l.months, Math.round(days / 30)) || 110 | years < 1.5 && substitute($l.year, 1) || 111 | substitute($l.years, Math.round(years)); 112 | 113 | var separator = $l.wordSeparator || ""; 114 | if ($l.wordSeparator === undefined) { separator = " "; } 115 | return $.trim([prefix, words, suffix].join(separator)); 116 | }, 117 | 118 | parse: function(iso8601) { 119 | var s = $.trim(iso8601); 120 | s = s.replace(/\.\d+/,""); // remove milliseconds 121 | s = s.replace(/-/,"/").replace(/-/,"/"); 122 | s = s.replace(/T/," ").replace(/Z/," UTC"); 123 | s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 124 | s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900 125 | return new Date(s); 126 | }, 127 | datetime: function(elem) { 128 | var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title"); 129 | return $t.parse(iso8601); 130 | }, 131 | isTime: function(elem) { 132 | // jQuery's `is()` doesn't play well with HTML5 in IE 133 | return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time"); 134 | } 135 | }); 136 | 137 | // functions that can be called via $(el).timeago('action') 138 | // init is default when no action is given 139 | // functions are called with context of a single element 140 | var functions = { 141 | init: function(){ 142 | var refresh_el = $.proxy(refresh, this); 143 | refresh_el(); 144 | var $s = $t.settings; 145 | if ($s.refreshMillis > 0) { 146 | this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis); 147 | } 148 | }, 149 | update: function(time){ 150 | var parsedTime = $t.parse(time); 151 | $(this).data('timeago', { datetime: parsedTime }); 152 | if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString()); 153 | refresh.apply(this); 154 | }, 155 | updateFromDOM: function(){ 156 | $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) }); 157 | refresh.apply(this); 158 | }, 159 | dispose: function () { 160 | if (this._timeagoInterval) { 161 | window.clearInterval(this._timeagoInterval); 162 | this._timeagoInterval = null; 163 | } 164 | } 165 | }; 166 | 167 | $.fn.timeago = function(action, options) { 168 | var fn = action ? functions[action] : functions.init; 169 | if(!fn){ 170 | throw new Error("Unknown function name '"+ action +"' for timeago"); 171 | } 172 | // each over objects here and call the requested function 173 | this.each(function(){ 174 | fn.call(this, options); 175 | }); 176 | return this; 177 | }; 178 | 179 | function refresh() { 180 | //check if it's still visible 181 | if(!$.contains(document.documentElement,this)){ 182 | //stop if it has been removed 183 | $(this).timeago("dispose"); 184 | return this; 185 | } 186 | 187 | var data = prepareData(this); 188 | var $s = $t.settings; 189 | 190 | if (!isNaN(data.datetime)) { 191 | if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) { 192 | $(this).text(inWords(data.datetime)); 193 | } 194 | } 195 | return this; 196 | } 197 | 198 | function prepareData(element) { 199 | element = $(element); 200 | if (!element.data("timeago")) { 201 | element.data("timeago", { datetime: $t.datetime(element) }); 202 | var text = $.trim(element.text()); 203 | if ($t.settings.localeTitle) { 204 | element.attr("title", element.data('timeago').datetime.toLocaleString()); 205 | } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) { 206 | element.attr("title", text); 207 | } 208 | } 209 | return element.data("timeago"); 210 | } 211 | 212 | function inWords(date) { 213 | return $t.inWords(distance(date)); 214 | } 215 | 216 | function distance(date) { 217 | return (new Date().getTime() - date.getTime()); 218 | } 219 | 220 | // fix for IE6 suckage 221 | document.createElement("abbr"); 222 | document.createElement("time"); 223 | })); -------------------------------------------------------------------------------- /public/jquery.devbridge-autocomplete.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ajax Autocomplete for jQuery, version 1.2.7 3 | * (c) 2013 Tomas Kirda 4 | * 5 | * Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. 6 | * For details, see the web site: http://www.devbridge.com/projects/autocomplete/jquery/ 7 | * 8 | */ 9 | (function(e){"function"===typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function g(a,b){var c=function(){},c={autoSelectFirst:!1,appendTo:"body",serviceUrl:null,lookup:null,onSelect:null,width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:g.formatResult,delimiter:null,zIndex:9999,type:"GET",noCache:!1,onSearchStart:c,onSearchComplete:c,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",lookupFilter:function(a,b,c){return-1!== 10 | a.value.toLowerCase().indexOf(c)},paramName:"query",transformResult:function(a){return"string"===typeof a?e.parseJSON(a):a}};this.element=a;this.el=e(a);this.suggestions=[];this.badQueries=[];this.selectedIndex=-1;this.currentValue=this.element.value;this.intervalId=0;this.cachedResponse=[];this.onChange=this.onChangeInterval=null;this.isLocal=this.ignoreValueChange=!1;this.suggestionsContainer=null;this.options=e.extend({},c,b);this.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"}; 11 | this.initialize();this.setOptions(b)}var h={extend:function(a,b){return e.extend(a,b)},createNode:function(a){var b=document.createElement("div");b.innerHTML=a;return b.firstChild}};g.utils=h;e.Autocomplete=g;g.formatResult=function(a,b){var c="("+b.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\)","g"),"\\$1")+")";return a.value.replace(RegExp(c,"gi"),"$1")};g.prototype={killerFn:null,initialize:function(){var a=this,b="."+a.classes.suggestion,c=a.classes.selected, 12 | d=a.options,f;a.element.setAttribute("autocomplete","off");a.killerFn=function(b){0===e(b.target).closest("."+a.options.containerClass).length&&(a.killSuggestions(),a.disableKillerFn())};if(!d.width||"auto"===d.width)d.width=a.el.outerWidth();a.suggestionsContainer=g.utils.createNode('');f=e(a.suggestionsContainer);f.appendTo(d.appendTo).width(d.width);f.on("mouseover.autocomplete",b,function(){a.activate(e(this).data("index"))}); 13 | f.on("mouseout.autocomplete",function(){a.selectedIndex=-1;f.children("."+c).removeClass(c)});f.on("click.autocomplete",b,function(){a.select(e(this).data("index"),!1)});a.fixPosition();if(window.opera)a.el.on("keypress.autocomplete",function(b){a.onKeyPress(b)});else a.el.on("keydown.autocomplete",function(b){a.onKeyPress(b)});a.el.on("keyup.autocomplete",function(b){a.onKeyUp(b)});a.el.on("blur.autocomplete",function(){a.onBlur()});a.el.on("focus.autocomplete",function(){a.fixPosition()})},onBlur:function(){this.enableKillerFn()}, 14 | setOptions:function(a){var b=this.options;h.extend(b,a);if(this.isLocal=e.isArray(b.lookup))b.lookup=this.verifySuggestionsFormat(b.lookup);e(this.suggestionsContainer).css({"max-height":b.maxHeight+"px",width:b.width+"px","z-index":b.zIndex})},clearCache:function(){this.cachedResponse=[];this.badQueries=[]},clear:function(){this.clearCache();this.currentValue=null;this.suggestions=[]},disable:function(){this.disabled=!0},enable:function(){this.disabled=!1},fixPosition:function(){var a;"body"===this.options.appendTo&& 15 | (a=this.el.offset(),e(this.suggestionsContainer).css({top:a.top+this.el.outerHeight()+"px",left:a.left+"px"}))},enableKillerFn:function(){e(document).on("click.autocomplete",this.killerFn)},disableKillerFn:function(){e(document).off("click.autocomplete",this.killerFn)},killSuggestions:function(){var a=this;a.stopKillSuggestions();a.intervalId=window.setInterval(function(){a.hide();a.stopKillSuggestions()},300)},stopKillSuggestions:function(){window.clearInterval(this.intervalId)},onKeyPress:function(a){if(!this.disabled&& 16 | !this.visible&&40===a.keyCode&&this.currentValue)this.suggest();else if(!this.disabled&&this.visible){switch(a.keyCode){case 27:this.el.val(this.currentValue);this.hide();break;case 9:case 13:if(-1===this.selectedIndex){this.hide();return}this.select(this.selectedIndex,13===a.keyCode);if(9===a.keyCode&&!1===this.options.tabDisabled)return;break;case 38:this.moveUp();break;case 40:this.moveDown();break;default:return}a.stopImmediatePropagation();a.preventDefault()}},onKeyUp:function(a){var b=this; 17 | if(!b.disabled){switch(a.keyCode){case 38:case 40:return}clearInterval(b.onChangeInterval);if(b.currentValue!==b.el.val())if(0'+a(e,b)+"
    "});f.html(g).show();this.visible=!0;this.options.autoSelectFirst&&(this.selectedIndex=0,f.children().first().addClass(d))}},verifySuggestionsFormat:function(a){return a.length&&"string"=== 21 | typeof a[0]?e.map(a,function(a){return{value:a,data:null}}):a},processResponse:function(a,b){var c=this.options,d=c.transformResult(a,b);d.suggestions=this.verifySuggestionsFormat(d.suggestions);c.noCache||(this.cachedResponse[d[c.paramName]]=d,0===d.suggestions.length&&this.badQueries.push(d[c.paramName]));b===this.getQuery(this.currentValue)&&(this.suggestions=d.suggestions,this.suggest())},activate:function(a){var b=this.classes.selected,c=e(this.suggestionsContainer),d=c.children();c.children("."+ 22 | b).removeClass(b);this.selectedIndex=a;return-1!==this.selectedIndex&&d.length>this.selectedIndex?(a=d.get(this.selectedIndex),e(a).addClass(b),a):null},select:function(a,b){var c=this.suggestions[a];c&&(this.el.val(c),this.ignoreValueChange=b,this.hide(),this.onSelect(a))},moveUp:function(){-1!==this.selectedIndex&&(0===this.selectedIndex?(e(this.suggestionsContainer).children().first().removeClass(this.classes.selected),this.selectedIndex=-1,this.el.val(this.currentValue)):this.adjustScroll(this.selectedIndex- 23 | 1))},moveDown:function(){this.selectedIndex!==this.suggestions.length-1&&this.adjustScroll(this.selectedIndex+1)},adjustScroll:function(a){var b=this.activate(a),c,d;b&&(b=b.offsetTop,c=e(this.suggestionsContainer).scrollTop(),d=c+this.options.maxHeight-25,bd&&e(this.suggestionsContainer).scrollTop(b-this.options.maxHeight+25),this.el.val(this.getValue(this.suggestions[a].value)))},onSelect:function(a){var b=this.options.onSelect;a=this.suggestions[a]; 24 | this.el.val(this.getValue(a.value));e.isFunction(b)&&b.call(this.element,a)},getValue:function(a){var b=this.options.delimiter,c;if(!b)return a;c=this.currentValue;b=c.split(b);return 1===b.length?a:c.substr(0,c.length-b[b.length-1].length)+a},dispose:function(){this.el.off(".autocomplete").removeData("autocomplete");this.disableKillerFn();e(this.suggestionsContainer).remove()}};e.fn.autocomplete=function(a,b){return 0===arguments.length?this.first().data("autocomplete"):this.each(function(){var c= 25 | e(this),d=c.data("autocomplete");if("string"===typeof a){if(d&&"function"===typeof d[a])d[a](b)}else d&&d.dispose&&d.dispose(),d=new g(this,a),c.data("autocomplete",d)})}}); -------------------------------------------------------------------------------- /application/thumb/ThumbBase.inc.php: -------------------------------------------------------------------------------- 1 | 9 | * Copyright (c) 2009, Ian Selby/Gen X Design 10 | * 11 | * Author(s): Ian Selby 12 | * 13 | * Licensed under the MIT License 14 | * Redistributions of files must retain the above copyright notice. 15 | * 16 | * @author Ian Selby 17 | * @copyright Copyright (c) 2009 Gen X Design 18 | * @link http://phpthumb.gxdlabs.com 19 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 20 | * @version 3.0 21 | * @package PhpThumb 22 | * @filesource 23 | */ 24 | 25 | /** 26 | * ThumbBase Class Definition 27 | * 28 | * This is the base class that all implementations must extend. It contains the 29 | * core variables and functionality common to all implementations, as well as the functions that 30 | * allow plugins to augment those classes. 31 | * 32 | * @package PhpThumb 33 | * @subpackage Core 34 | */ 35 | abstract class ThumbBase 36 | { 37 | /** 38 | * All imported objects 39 | * 40 | * An array of imported plugin objects 41 | * 42 | * @var array 43 | */ 44 | protected $imported; 45 | /** 46 | * All imported object functions 47 | * 48 | * An array of all methods added to this class by imported plugin objects 49 | * 50 | * @var array 51 | */ 52 | protected $importedFunctions; 53 | /** 54 | * The last error message raised 55 | * 56 | * @var string 57 | */ 58 | protected $errorMessage; 59 | /** 60 | * Whether or not the current instance has any errors 61 | * 62 | * @var bool 63 | */ 64 | protected $hasError; 65 | /** 66 | * The name of the file we're manipulating 67 | * 68 | * This must include the path to the file (absolute paths recommended) 69 | * 70 | * @var string 71 | */ 72 | protected $fileName; 73 | /** 74 | * What the file format is (mime-type) 75 | * 76 | * @var string 77 | */ 78 | protected $format; 79 | /** 80 | * Whether or not the image is hosted remotely 81 | * 82 | * @var bool 83 | */ 84 | protected $remoteImage; 85 | /** 86 | * Whether or not the current image is an actual file, or the raw file data 87 | * 88 | * By "raw file data" it's meant that we're actually passing the result of something 89 | * like file_get_contents() or perhaps from a database blob 90 | * 91 | * @var bool 92 | */ 93 | protected $isDataStream; 94 | 95 | /** 96 | * Class constructor 97 | * 98 | * @return ThumbBase 99 | */ 100 | public function __construct ($fileName, $isDataStream = false) 101 | { 102 | $this->imported = array(); 103 | $this->importedFunctions = array(); 104 | $this->errorMessage = null; 105 | $this->hasError = false; 106 | $this->fileName = $fileName; 107 | $this->remoteImage = false; 108 | $this->isDataStream = $isDataStream; 109 | 110 | $this->fileExistsAndReadable(); 111 | } 112 | 113 | /** 114 | * Imports plugins in $registry to the class 115 | * 116 | * @param array $registry 117 | */ 118 | public function importPlugins ($registry) 119 | { 120 | foreach ($registry as $plugin => $meta) 121 | { 122 | $this->imports($plugin); 123 | } 124 | } 125 | 126 | /** 127 | * Imports a plugin 128 | * 129 | * This is where all the plugins magic happens! This function "loads" the plugin functions, making them available as 130 | * methods on the class. 131 | * 132 | * @param string $object The name of the object to import / "load" 133 | */ 134 | protected function imports ($object) 135 | { 136 | // the new object to import 137 | $newImport = new $object(); 138 | // the name of the new object (class name) 139 | $importName = get_class($newImport); 140 | // the new functions to import 141 | $importFunctions = get_class_methods($newImport); 142 | 143 | // add the object to the registry 144 | array_push($this->imported, array($importName, $newImport)); 145 | 146 | // add the methods to the registry 147 | foreach ($importFunctions as $key => $functionName) 148 | { 149 | $this->importedFunctions[$functionName] = &$newImport; 150 | } 151 | } 152 | 153 | /** 154 | * Checks to see if $this->fileName exists and is readable 155 | * 156 | */ 157 | protected function fileExistsAndReadable () 158 | { 159 | if ($this->isDataStream === true) 160 | { 161 | return; 162 | } 163 | 164 | if (stristr($this->fileName, 'http://') !== false) 165 | { 166 | $this->remoteImage = true; 167 | return; 168 | } 169 | 170 | if (!file_exists($this->fileName)) 171 | { 172 | $this->triggerError('Image file not found: ' . $this->fileName); 173 | } 174 | elseif (!is_readable($this->fileName)) 175 | { 176 | $this->triggerError('Image file not readable: ' . $this->fileName); 177 | } 178 | } 179 | 180 | /** 181 | * Sets $this->errorMessage to $errorMessage and throws an exception 182 | * 183 | * Also sets $this->hasError to true, so even if the exceptions are caught, we don't 184 | * attempt to proceed with any other functions 185 | * 186 | * @param string $errorMessage 187 | */ 188 | protected function triggerError ($errorMessage) 189 | { 190 | $this->hasError = true; 191 | $this->errorMessage = $errorMessage; 192 | 193 | throw new Exception ($errorMessage); 194 | } 195 | 196 | /** 197 | * Calls plugin / imported functions 198 | * 199 | * This is also where a fair amount of plugins magaic happens. This magic method is called whenever an "undefined" class 200 | * method is called in code, and we use that to call an imported function. 201 | * 202 | * You should NEVER EVER EVER invoke this function manually. The universe will implode if you do... seriously ;) 203 | * 204 | * @param string $method 205 | * @param array $args 206 | */ 207 | public function __call ($method, $args) 208 | { 209 | if( array_key_exists($method, $this->importedFunctions)) 210 | { 211 | $args[] = $this; 212 | return call_user_func_array(array($this->importedFunctions[$method], $method), $args); 213 | } 214 | 215 | throw new BadMethodCallException ('Call to undefined method/class function: ' . $method); 216 | } 217 | 218 | /** 219 | * Returns $imported. 220 | * @see ThumbBase::$imported 221 | * @return array 222 | */ 223 | public function getImported () 224 | { 225 | return $this->imported; 226 | } 227 | 228 | /** 229 | * Returns $importedFunctions. 230 | * @see ThumbBase::$importedFunctions 231 | * @return array 232 | */ 233 | public function getImportedFunctions () 234 | { 235 | return $this->importedFunctions; 236 | } 237 | 238 | /** 239 | * Returns $errorMessage. 240 | * 241 | * @see ThumbBase::$errorMessage 242 | */ 243 | public function getErrorMessage () 244 | { 245 | return $this->errorMessage; 246 | } 247 | 248 | /** 249 | * Sets $errorMessage. 250 | * 251 | * @param object $errorMessage 252 | * @see ThumbBase::$errorMessage 253 | */ 254 | public function setErrorMessage ($errorMessage) 255 | { 256 | $this->errorMessage = $errorMessage; 257 | } 258 | 259 | /** 260 | * Returns $fileName. 261 | * 262 | * @see ThumbBase::$fileName 263 | */ 264 | public function getFileName () 265 | { 266 | return $this->fileName; 267 | } 268 | 269 | /** 270 | * Sets $fileName. 271 | * 272 | * @param object $fileName 273 | * @see ThumbBase::$fileName 274 | */ 275 | public function setFileName ($fileName) 276 | { 277 | $this->fileName = $fileName; 278 | } 279 | 280 | /** 281 | * Returns $format. 282 | * 283 | * @see ThumbBase::$format 284 | */ 285 | public function getFormat () 286 | { 287 | return $this->format; 288 | } 289 | 290 | /** 291 | * Sets $format. 292 | * 293 | * @param object $format 294 | * @see ThumbBase::$format 295 | */ 296 | public function setFormat ($format) 297 | { 298 | $this->format = $format; 299 | } 300 | 301 | /** 302 | * Returns $hasError. 303 | * 304 | * @see ThumbBase::$hasError 305 | */ 306 | public function getHasError () 307 | { 308 | return $this->hasError; 309 | } 310 | 311 | /** 312 | * Sets $hasError. 313 | * 314 | * @param object $hasError 315 | * @see ThumbBase::$hasError 316 | */ 317 | public function setHasError ($hasError) 318 | { 319 | $this->hasError = $hasError; 320 | } 321 | 322 | 323 | } 324 | -------------------------------------------------------------------------------- /application/securimage/example_form.ajax.php: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | Securimage Example Form 21 | 29 | 30 | 31 | 32 |
    33 | Example Form 34 | 35 |

    36 | This is an example PHP form that processes user information, checks for errors, and validates the captcha code.
    37 | This example form also demonstrates how to submit a form to itself to display error messages. 38 |

    39 | 40 | 41 | 42 |
    43 | 44 | 45 |

    46 | Name*:
    47 | 48 |

    49 | 50 |

    51 | Email*:
    52 | 53 |

    54 | 55 |

    56 | URL:
    57 | 58 |

    59 | 60 |

    61 | Message*:
    62 | 63 |

    64 | 65 |

    66 | CAPTCHA Image 67 | 68 | 69 | 70 |   71 | Reload Image
    72 | Enter Code*:
    73 | 74 |

    75 | 76 |

    77 |
    78 | 79 |

    80 | 81 |
    82 |
    83 | 84 | 85 | 114 | 115 | 116 | 117 | 118 | $value) { 127 | if (!is_array($key)) { 128 | // sanitize the input data 129 | if ($key != 'ct_message') $value = strip_tags($value); 130 | $_POST[$key] = htmlspecialchars(stripslashes(trim($value))); 131 | } 132 | } 133 | 134 | $name = @$_POST['ct_name']; // name from the form 135 | $email = @$_POST['ct_email']; // email from the form 136 | $URL = @$_POST['ct_URL']; // url from the form 137 | $message = @$_POST['ct_message']; // the message from the form 138 | $captcha = @$_POST['ct_captcha']; // the user's entry for the captcha code 139 | $name = substr($name, 0, 64); // limit name to 64 characters 140 | 141 | $errors = array(); // initialize empty error array 142 | 143 | if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE'] == false) { 144 | // only check for errors if the form is not in debug mode 145 | 146 | if (strlen($name) < 3) { 147 | // name too short, add error 148 | $errors['name_error'] = 'Your name is required'; 149 | } 150 | 151 | if (strlen($email) == 0) { 152 | // no email address given 153 | $errors['email_error'] = 'Email address is required'; 154 | } else if ( !preg_match('/^(?:[\w\d]+\.?)+@(?:(?:[\w\d]\-?)+\.)+\w{2,4}$/i', $email)) { 155 | // invalid email format 156 | $errors['email_error'] = 'Email address entered is invalid'; 157 | } 158 | 159 | if (strlen($message) < 20) { 160 | // message length too short 161 | $errors['message_error'] = 'Please enter a message'; 162 | } 163 | } 164 | 165 | // Only try to validate the captcha if the form has no errors 166 | // This is especially important for ajax calls 167 | if (sizeof($errors) == 0) { 168 | require_once dirname(__FILE__) . '/securimage.php'; 169 | $securimage = new Securimage(); 170 | 171 | if ($securimage->check($captcha) == false) { 172 | $errors['captcha_error'] = 'Incorrect security code entered'; 173 | } 174 | } 175 | 176 | if (sizeof($errors) == 0) { 177 | // no errors, send the form 178 | $time = date('r'); 179 | $message = "A message was submitted from the contact form. The following information was provided.

    " 180 | . "Name: $name
    " 181 | . "Email: $email
    " 182 | . "URL: $URL
    " 183 | . "Message:
    " 184 | . "
    $message
    " 185 | . "

    IP Address: {$_SERVER['REMOTE_ADDR']}
    " 186 | . "Time: $time
    " 187 | . "Browser: {$_SERVER['HTTP_USER_AGENT']}
    "; 188 | 189 | if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE'] == false) { 190 | // send the message with mail() 191 | mail($GLOBALS['ct_recipient'], $GLOBALS['ct_msg_subject'], $message, "From: {$GLOBALS['ct_recipient']}\r\nReply-To: {$email}\r\nContent-type: text/html; charset=ISO-8859-1\r\nMIME-Version: 1.0"); 192 | } 193 | 194 | $return = array('error' => 0, 'message' => 'OK'); 195 | die(json_encode($return)); 196 | } else { 197 | $errmsg = ''; 198 | foreach($errors as $key => $error) { 199 | // set up error messages to display with each field 200 | $errmsg .= " - {$error}\n"; 201 | } 202 | 203 | $return = array('error' => 1, 'message' => $errmsg); 204 | die(json_encode($return)); 205 | } 206 | } // POST 207 | } // function process_si_contact_form() 208 | -------------------------------------------------------------------------------- /application/securimage/README.txt: -------------------------------------------------------------------------------- 1 | NAME: 2 | 3 | Securimage - A PHP class for creating captcha images and audio with many options. 4 | 5 | VERSION: 6 | 7 | 3.5.2 8 | 9 | AUTHOR: 10 | 11 | Drew Phillips 12 | 13 | DOWNLOAD: 14 | 15 | The latest version can always be 16 | found at http://www.phpcaptcha.org 17 | 18 | DOCUMENTATION: 19 | 20 | Online documentation of the class, methods, and variables can 21 | be found at http://www.phpcaptcha.org/Securimage_Docs/ 22 | 23 | REQUIREMENTS: 24 | 25 | PHP 5.2 or greater 26 | GD 2.0 27 | FreeType (Required, for TTF fonts) 28 | PDO (if using Sqlite, MySQL, or PostgreSQL) 29 | 30 | SYNOPSIS: 31 | 32 | require_once 'securimage.php'; 33 | 34 | **Within your HTML form** 35 | 36 |
    37 | .. form elements 38 | 39 |
    40 | 41 |
    42 |
    43 | 44 | 45 | **Within your PHP form processor** 46 | 47 | // Code Validation 48 | 49 | $image = new Securimage(); 50 | if ($image->check($_POST['captcha_code']) == true) { 51 | echo "Correct!"; 52 | } else { 53 | echo "Sorry, wrong code."; 54 | } 55 | 56 | DESCRIPTION: 57 | 58 | What is Securimage? 59 | 60 | Securimage is a PHP class that is used to generate and validate CAPTCHA 61 | images. 62 | 63 | The classes uses an existing PHP session or creates its own if 64 | none is found to store the CAPTCHA code. In addition, a database can be 65 | used instead of session storage. 66 | 67 | Variables within the class are used to control the style and display of 68 | the image. The class uses TTF fonts and effects for strengthening the 69 | security of the image. 70 | 71 | It also creates audible codes which are played for visually impared users. 72 | 73 | COPYRIGHT: 74 | 75 | Copyright (c) 2014 Drew Phillips 76 | All rights reserved. 77 | 78 | Redistribution and use in source and binary forms, with or without 79 | modification, are permitted provided that the following conditions are met: 80 | 81 | - Redistributions of source code must retain the above copyright notice, 82 | this list of conditions and the following disclaimer. 83 | - Redistributions in binary form must reproduce the above copyright notice, 84 | this list of conditions and the following disclaimer in the documentation 85 | and/or other materials provided with the distribution. 86 | 87 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 88 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 89 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 90 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 91 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 92 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 93 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 94 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 95 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 96 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 97 | POSSIBILITY OF SUCH DAMAGE. 98 | 99 | LICENSES: 100 | 101 | The WavFile.php class used in Securimage by Drew Phillips and Paul Voegler 102 | is used under the BSD License. See WavFile.php for details. 103 | Many thanks to Paul Voegler (http://www.voegler.eu/) for contributing to 104 | Securimage. 105 | 106 | --------------------------------------------------------------------------- 107 | Flash code created by Age Bosma & Mario Romero (animario@hotmail.com) 108 | Many thanks for releasing this to the project! 109 | 110 | --------------------------------------------------------------------------- 111 | Portions of Securimage contain code from Han-Kwang Nienhuys' PHP captcha 112 | 113 | Han-Kwang Nienhuys' PHP captcha 114 | Copyright June 2007 115 | 116 | This copyright message and attribution must be preserved upon 117 | modification. Redistribution under other licenses is expressly allowed. 118 | Other licenses include GPL 2 or higher, BSD, and non-free licenses. 119 | The original, unrestricted version can be obtained from 120 | http://www.lagom.nl/linux/hkcaptcha/ 121 | 122 | --------------------------------------------------------------------------- 123 | AHGBold.ttf (AlteHaasGroteskBold.ttf) font was created by Yann Le Coroller 124 | and is distributed as freeware. 125 | 126 | Alte Haas Grotesk is a typeface that look like an helvetica printed in an 127 | old Muller-Brockmann Book. 128 | 129 | These fonts are freeware and can be distributed as long as they are 130 | together with this text file. 131 | 132 | I would appreciate very much to see what you have done with it anyway. 133 | 134 | yann le coroller 135 | www.yannlecoroller.com 136 | yann@lecoroller.com 137 | 138 | --------------------------------------------------------------------------- 139 | Portions of securimage_play.swf use the PopForge flash library for 140 | playing audio 141 | 142 | /** 143 | * Copyright(C) 2007 Andre Michelle and Joa Ebert 144 | * 145 | * PopForge is an ActionScript3 code sandbox developed by Andre Michelle 146 | * and Joa Ebert 147 | * http://sandbox.popforge.de 148 | * 149 | * PopforgeAS3Audio is free software; you can redistribute it and/or modify 150 | * it under the terms of the GNU General Public License as published by 151 | * the Free Software Foundation; either version 3 of the License, or 152 | * (at your option) any later version. 153 | * 154 | * PopforgeAS3Audio is distributed in the hope that it will be useful, 155 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 156 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 157 | * GNU General Public License for more details. 158 | * 159 | * You should have received a copy of the GNU General Public License 160 | * along with this program. If not, see 161 | */ 162 | 163 | -------------------------------------------------------------------------- 164 | Some graphics used are from the Humility Icon Pack by WorLord 165 | 166 | License: GNU/GPL (http://findicons.com/pack/1723/humility) 167 | http://findicons.com/icon/192558/gnome_volume_control 168 | http://findicons.com/icon/192562/gtk_refresh 169 | 170 | -------------------------------------------------------------------------- 171 | Background noise sound files are from SoundJay.com 172 | http://www.soundjay.com/tos.html 173 | 174 | All sound effects on this website are created by us and protected under 175 | the copyright laws, international treaty provisions and other applicable 176 | laws. By downloading sounds, music or any material from this site implies 177 | that you have read and accepted these terms and conditions: 178 | 179 | Sound Effects 180 | You are allowed to use the sounds free of charge and royalty free in your 181 | projects (such as films, videos, games, presentations, animations, stage 182 | plays, radio plays, audio books, apps) be it for commercial or 183 | non-commercial purposes. 184 | 185 | But you are NOT allowed to 186 | - post the sounds (as sound effects or ringtones) on any website for 187 | others to download, copy or use 188 | - use them as a raw material to create sound effects or ringtones that 189 | you will sell, distribute or offer for downloading 190 | - sell, re-sell, license or re-license the sounds (as individual sound 191 | effects or as a sound effects library) to anyone else 192 | - claim the sounds as yours 193 | - link directly to individual sound files 194 | - distribute the sounds in apps or computer programs that are clearly 195 | sound related in nature (such as sound machine, sound effect 196 | generator, ringtone maker, funny sounds app, sound therapy app, etc.) 197 | or in apps or computer programs that use the sounds as the program's 198 | sound resource library for other people's use (such as animation 199 | creator, digital book creator, song maker software, etc.). If you are 200 | developing such computer programs, contact us for licensing options. 201 | 202 | If you use the sound effects, please consider giving us a credit and 203 | linking back to us but it's not required. 204 | 205 | -------------------------------------------------------------------------------- /application/securimage/example_form.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | Securimage Example Form 17 | 28 | 29 | 30 | 31 |
    32 | Example Form 33 | 34 |

    35 | This is an example PHP form that processes user information, checks for errors, and validates the captcha code.
    36 | This example form also demonstrates how to submit a form to itself to display error messages. 37 |

    38 | 39 | 44 |
    There was a problem with your submission. Errors are displayed below in red.

    45 | 46 |
    The captcha was correct and the message has been sent! The captcha was solved in seconds.

    47 | 48 | 49 |
    50 | 51 | 52 |

    53 | 54 | 55 | 56 |

    57 | 58 |

    59 | 60 | 61 | 62 |

    63 | 64 |

    65 | 66 | 67 | 68 |

    69 | 70 |

    71 | 72 | 73 | 74 |

    75 | 76 |

    77 | 90 |

    91 | 92 |

    93 |
    94 | 95 |

    96 | 97 |
    98 |
    99 | 100 | 101 | 102 | 103 | $value) { 114 | if (!is_array($key)) { 115 | // sanitize the input data 116 | if ($key != 'ct_message') $value = strip_tags($value); 117 | $_POST[$key] = htmlspecialchars(stripslashes(trim($value))); 118 | } 119 | } 120 | 121 | $name = @$_POST['ct_name']; // name from the form 122 | $email = @$_POST['ct_email']; // email from the form 123 | $URL = @$_POST['ct_URL']; // url from the form 124 | $message = @$_POST['ct_message']; // the message from the form 125 | $captcha = @$_POST['ct_captcha']; // the user's entry for the captcha code 126 | $name = substr($name, 0, 64); // limit name to 64 characters 127 | 128 | $errors = array(); // initialize empty error array 129 | 130 | if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE'] == false) { 131 | // only check for errors if the form is not in debug mode 132 | 133 | if (strlen($name) < 3) { 134 | // name too short, add error 135 | $errors['name_error'] = 'Your name is required'; 136 | } 137 | 138 | if (strlen($email) == 0) { 139 | // no email address given 140 | $errors['email_error'] = 'Email address is required'; 141 | } else if ( !preg_match('/^(?:[\w\d]+\.?)+@(?:(?:[\w\d]\-?)+\.)+\w{2,4}$/i', $email)) { 142 | // invalid email format 143 | $errors['email_error'] = 'Email address entered is invalid'; 144 | } 145 | 146 | if (strlen($message) < 20) { 147 | // message length too short 148 | $errors['message_error'] = 'Your message must be longer than 20 characters'; 149 | } 150 | } 151 | 152 | // Only try to validate the captcha if the form has no errors 153 | // This is especially important for ajax calls 154 | if (sizeof($errors) == 0) { 155 | require_once dirname(__FILE__) . '/securimage.php'; 156 | $securimage = new Securimage(); 157 | 158 | if ($securimage->check($captcha) == false) { 159 | $errors['captcha_error'] = 'Incorrect security code entered
    '; 160 | } 161 | } 162 | 163 | if (sizeof($errors) == 0) { 164 | // no errors, send the form 165 | $time = date('r'); 166 | $message = "A message was submitted from the contact form. The following information was provided.

    " 167 | . "Name: $name
    " 168 | . "Email: $email
    " 169 | . "URL: $URL
    " 170 | . "Message:
    " 171 | . "
    $message
    " 172 | . "

    IP Address: {$_SERVER['REMOTE_ADDR']}
    " 173 | . "Time: $time
    " 174 | . "Browser: {$_SERVER['HTTP_USER_AGENT']}
    "; 175 | 176 | $message = wordwrap($message, 70); 177 | 178 | if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE'] == false) { 179 | // send the message with mail() 180 | mail($GLOBALS['ct_recipient'], $GLOBALS['ct_msg_subject'], $message, "From: {$GLOBALS['ct_recipient']}\r\nReply-To: {$email}\r\nContent-type: text/html; charset=UTF-8\r\nMIME-Version: 1.0"); 181 | } 182 | 183 | $_SESSION['ctform']['timetosolve'] = $securimage->getTimeToSolve(); 184 | $_SESSION['ctform']['error'] = false; // no error with form 185 | $_SESSION['ctform']['success'] = true; // message sent 186 | } else { 187 | // save the entries, this is to re-populate the form 188 | $_SESSION['ctform']['ct_name'] = $name; // save name from the form submission 189 | $_SESSION['ctform']['ct_email'] = $email; // save email 190 | $_SESSION['ctform']['ct_URL'] = $URL; // save URL 191 | $_SESSION['ctform']['ct_message'] = $message; // save message 192 | 193 | foreach($errors as $key => $error) { 194 | // set up error messages to display with each field 195 | $_SESSION['ctform'][$key] = "$error"; 196 | } 197 | 198 | $_SESSION['ctform']['error'] = true; // set error floag 199 | } 200 | } // POST 201 | } 202 | 203 | $_SESSION['ctform']['success'] = false; // clear success value after running 204 | -------------------------------------------------------------------------------- /application/controllers/userController.php: -------------------------------------------------------------------------------- 1 | model->searchUser($words); 10 | $callback=array(); 11 | foreach($result as $k=>$v){ 12 | $callback[$k]['value']=$v['username']; 13 | $callback[$k]['data']=$v['uid']; 14 | } 15 | echo json_encode(array('suggestions'=>$callback)); 16 | } 17 | } 18 | public function avatarHover(){ 19 | $uid=intval($_POST['uid']); 20 | $callback=array( 21 | 'status'=>false 22 | ); 23 | if($uid>0){ 24 | $user_info=$this->model->getUserInfoByUid($uid); 25 | $user['profile_url']=url('user/index',array('uid'=>$user_info['uid'])); 26 | $user['big_avatar']=get_avatar($user_info['big_avatar'],'big'); 27 | $user['username']=$user_info['username']; 28 | $user['ban_send_msg']=$user_info['ban_send_msg']; 29 | $user['thread_num']=$user_info['thread_num']; 30 | $user['reply_num']=$user_info['reply_num']; 31 | $user['collect_num']=$user_info['collect_num']; 32 | $user['intro']=$user_info['intro']==''?'该用户暂无自我介绍':$user_info['intro']; 33 | $user['thread_url']=url('user/thread',array('uid'=>$uid,'last_id'=>0,'direction'=>1)); 34 | $user['collect_url']=url('user/collect',array('uid'=>$uid,'last_id'=>0,'direction'=>1)); 35 | $user['reply_url']=url('user/reply',array('uid'=>$uid,'last_id'=>0,'direction'=>1)); 36 | if($this->uid){ 37 | $vote_interaction=$this->model->getUserVoteInteraction($this->uid,$uid); 38 | $reply_interaction=$this->model->getUserReplyInteraction($this->uid,$uid); 39 | $user['vote_interaction']=$vote_interaction==null?0:$vote_interaction; 40 | $user['reply_interaction']=$reply_interaction==null?0:$reply_interaction; 41 | $user['send_msg_url']=url('profile/msg'); 42 | } 43 | $callback=array( 44 | 'status'=>true, 45 | 'user_info'=>$user 46 | ); 47 | } 48 | echo json_encode($callback); 49 | } 50 | public function index($uid){ 51 | $uid=intval($uid); 52 | if($uid>0){ 53 | $user_info=$this->model->getUserInfoByUid($uid); 54 | $this->set('user_info',$user_info); 55 | if($this->uid&&$this->uid!=$uid){ 56 | $vote_interaction=$this->model->getUserVoteInteraction($this->uid,$uid)==null; 57 | $reply_interaction=$this->model->getUserReplyInteraction($this->uid,$uid); 58 | $this->set('vote_interaction',$vote_interaction==null?0:$vote_interaction); 59 | $this->set('reply_interaction',$reply_interaction==null?0:$vote_interaction); 60 | } 61 | $this->set('user_cur','info'); 62 | $this->set('breadcrumb',' ›
  • 63 | 64 |

    '.$user_info['username'].'个人主页

    65 |
    66 | 67 |
  • '); 68 | $this->set('title',$user_info['username'].'个人主页 | '.$this->config['shortname']); 69 | $this->render('user_info'); 70 | } 71 | } 72 | public function thread($uid,$last_id,$direction){ 73 | $uid=intval($uid); 74 | if($uid>0) { 75 | $user_info = $this->model->getUserInfoByUid($uid); 76 | $this->set('user_info', $user_info); 77 | if($user_info['ban_view_thread']!=1){ 78 | $thread_list=$this->model('main')->getThreads('user_thread'.$uid,$last_id,$direction); 79 | $thread=pagination($thread_list,$direction,$last_id,$this->config['thread_per_page']); 80 | $prev=$thread['prev']!=''?url('user/thread',array('uid'=>$uid,'last_id'=>$thread['prev'],'direction'=>0)):''; 81 | $next=$thread['next']!=''?url('user/thread',array('uid'=>$uid,'last_id'=>$thread['next'],'direction'=>1)):''; 82 | $this->set('thread_list',$thread['arr']); 83 | $this->set('prev',$prev); 84 | $this->set('next',$next); 85 | } 86 | $this->set('title',$user_info['username'].'最近发表的帖子 | '.$user_info['username'].'个人主页 | '.$this->config['shortname']); 87 | $this->set('user_cur',__FUNCTION__); 88 | $this->set('breadcrumb',' ›
  • 89 | 90 | '.$user_info['username'].'个人主页 91 | 92 | 93 |
  • 94 | 95 |

    '.$user_info['username'].'最近发表的帖子(共发布了'.$user_info['thread_num'].'篇帖子)

    96 |
    97 | 98 |
  • '); 99 | } 100 | $this->render('user_thread'); 101 | } 102 | public function collect($uid,$last_id,$direction){ 103 | $uid=intval($uid); 104 | if($uid>0) { 105 | $user_info = $this->model->getUserInfoByUid($uid); 106 | $this->set('user_info', $user_info); 107 | if($user_info['ban_view_collect']!=1){ 108 | $thread_list=$this->model('main')->getThreads('user_collect'.$uid,$last_id,$direction); 109 | $thread=pagination($thread_list,$direction,$last_id,$this->config['thread_per_page']); 110 | $prev=$thread['prev']!=''?url('user/collect',array('uid'=>$uid,'last_id'=>$thread['prev'],'direction'=>0)):''; 111 | $next=$thread['next']!=''?url('user/collect',array('uid'=>$uid,'last_id'=>$thread['next'],'direction'=>1)):''; 112 | $this->set('thread_list',$thread['arr']); 113 | $this->set('prev',$prev); 114 | $this->set('next',$next); 115 | } 116 | $this->set('title',$user_info['username'].'收藏的帖子 | '.$user_info['username'].'个人主页 | '.$this->config['shortname']); 117 | $this->set('user_cur',__FUNCTION__); 118 | $this->set('breadcrumb',' ›
  • 119 | 120 | '.$user_info['username'].'个人主页 121 | 122 | 123 |
  • 124 | 125 |

    '.$user_info['username'].'收藏的帖子(共收集了'.$user_info['collect_num'].'篇帖子)

    126 |
    127 | 128 |
  • '); 129 | } 130 | $this->render('user_collect'); 131 | } 132 | public function reply($uid,$last_id,$direction){ 133 | $uid=intval($uid); 134 | if($uid>0){ 135 | $last_id=intval($last_id); 136 | $direction=intval($direction); 137 | $user_info = $this->model->getUserInfoByUid($uid); 138 | if($user_info['ban_view_reply']!=1){ 139 | $reply_list=$this->model('reply')->getUserPostReplies($uid,$last_id,$direction); 140 | $page=pagination($reply_list,$direction,$last_id,$this->config['reply_per_page']); 141 | $prev=$page['prev']!=''?url('user/reply',array('uid'=>$uid,'last_id'=>$page['prev'],'direction'=>0)):''; 142 | $next=$page['next']!=''?url('user/reply',array('uid'=>$uid,'last_id'=>$page['next'],'direction'=>1)):''; 143 | $this->set('reply',$page['arr']); 144 | $this->set('prev',$prev); 145 | $this->set('next',$next); 146 | } 147 | $this->set('user_info', $user_info); 148 | $this->set('user_cur',__FUNCTION__); 149 | $this->set('breadcrumb',' ›
  • 150 | 151 | '.$user_info['username'].'个人主页 152 | 153 | 154 |
  • 155 | 156 |

    '.$user_info['username'].'回复过的帖子

    157 |
    158 | 159 |
  • '); 160 | $this->set('title',$user_info['username'].'回复过的帖子 | '.$user_info['username'].'个人主页 | '.$this->config['shortname']); 161 | } 162 | $this->render('user_reply'); 163 | } 164 | public function freezeUser(){ 165 | $uid=intval($_POST['uid']); 166 | if($uid>0){ 167 | if($this->uid==1){ 168 | $this->model->freezeUser($uid); 169 | $callback=array( 170 | 'status'=>true 171 | ); 172 | }else{ 173 | $callback=array( 174 | 'status'=>false, 175 | 'msg'=>'无此操作权限' 176 | ); 177 | } 178 | }else{ 179 | $callback=array( 180 | 'status'=>false, 181 | 'msg'=>'参数错误' 182 | ); 183 | } 184 | echo json_encode($callback); 185 | } 186 | } 187 | ?> --------------------------------------------------------------------------------