From 41681f1f1864ccd464b32eb86f854053b03495f6 Mon Sep 17 00:00:00 2001 From: October Date: Wed, 26 Mar 2014 14:18:20 +0800 Subject: [PATCH] first commit --- .gitignore | 2 + config.yaml | 5 + config/app.config.php | 4 + config/db.config.php | 15 + controllers/callback.class.php | 39 ++ controllers/main.class.php | 15 + engine/Autoloader.class.php | 26 + engine/config/core.config.php | 9 + engine/init.inc.php | 19 + engine/lib/Cache.class.php | 38 ++ engine/lib/Cdn.class.php | 41 ++ engine/lib/Db.class.php | 444 +++++++++++++++ engine/lib/IFCookie.class.php | 19 + engine/lib/Icon.class.php | 117 ++++ engine/lib/Lock.class.php | 51 ++ engine/lib/Mysql.class.php | 137 +++++ engine/lib/SafeHtml.class.php | 676 ++++++++++++++++++++++ engine/lib/Thumbnail.class.php | 167 ++++++ engine/lib/Url.class.php | 147 +++++ engine/lib/Weibo.class.php | 64 +++ engine/lib/XML/HTMLSax3.php | 688 +++++++++++++++++++++++ engine/lib/XML/HTMLSax3/Decorators.php | 363 ++++++++++++ engine/lib/XML/HTMLSax3/States.php | 287 ++++++++++ engine/lib/core.function.php | 140 +++++ index.php | 29 + js/core.js | 750 +++++++++++++++++++++++++ lib/BaseController.class.php | 83 +++ lib/app.function.php | 99 ++++ readme.md | 1 + themes/default/layout.tpl.html | 21 + themes/default/main.tpl.html | 0 31 files changed, 4496 insertions(+) create mode 100644 .gitignore create mode 100644 config.yaml create mode 100755 config/app.config.php create mode 100755 config/db.config.php create mode 100755 controllers/callback.class.php create mode 100644 controllers/main.class.php create mode 100755 engine/Autoloader.class.php create mode 100755 engine/config/core.config.php create mode 100755 engine/init.inc.php create mode 100755 engine/lib/Cache.class.php create mode 100644 engine/lib/Cdn.class.php create mode 100644 engine/lib/Db.class.php create mode 100644 engine/lib/IFCookie.class.php create mode 100755 engine/lib/Icon.class.php create mode 100755 engine/lib/Lock.class.php create mode 100644 engine/lib/Mysql.class.php create mode 100755 engine/lib/SafeHtml.class.php create mode 100755 engine/lib/Thumbnail.class.php create mode 100755 engine/lib/Url.class.php create mode 100755 engine/lib/Weibo.class.php create mode 100644 engine/lib/XML/HTMLSax3.php create mode 100644 engine/lib/XML/HTMLSax3/Decorators.php create mode 100644 engine/lib/XML/HTMLSax3/States.php create mode 100755 engine/lib/core.function.php create mode 100644 index.php create mode 100755 js/core.js create mode 100755 lib/BaseController.class.php create mode 100755 lib/app.function.php create mode 100644 readme.md create mode 100755 themes/default/layout.tpl.html create mode 100644 themes/default/main.tpl.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..242ef13 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +.svn diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..eac30d0 --- /dev/null +++ b/config.yaml @@ -0,0 +1,5 @@ +--- +name: engine +version: 1 +handle: + - rewrite: if(!is_dir() && !is_file()) goto "index.php?%{QUERY_STRING}" diff --git a/config/app.config.php b/config/app.config.php new file mode 100755 index 0000000..7ea7d17 --- /dev/null +++ b/config/app.config.php @@ -0,0 +1,4 @@ + $value) { + $_SESSION[$key] = $value; + } + $_SESSION['__SINA']['TOKEN'] = $token; + }else{ + die( 'REST API ERROR!' ); + } + $_SESSION['expiresTime'] = time() + $token['remind_in']; + $_SESSION['__SINA']['TOKEN'] = $token['access_token']; + $_SESSION['uid'] = $token['uid'] ; + $uid=$_SESSION['uid']; + + + if( $_SESSION['backUrl'] ){ + if( strpos( $_SESSION['backUrl'] , '?' ) === false ){ + $backUrl = $_SESSION['backUrl'].'?viewer='.$_SESSION['uid']; + }else{ + $backUrl = $_SESSION['backUrl'].'&viewer='.$_SESSION['uid']; + } + header("Location: ".$backUrl ); + }else{ + header('Location: http://'.$_SERVER['HTTP_HOST'].'/'); + } + } + }else{ + die( '
只有授权后才能进入应用
' ); + } + } +} \ No newline at end of file diff --git a/controllers/main.class.php b/controllers/main.class.php new file mode 100644 index 0000000..2bb0cca --- /dev/null +++ b/controllers/main.class.php @@ -0,0 +1,15 @@ +


'; + echo 'isAjax:'.isAjax(); + echo Url::getMethod(); + echo Url::$url; + $this->render(); + } + public function test(){ + print_r( $_REQUEST ); + echo 'isAjax:'.isAjax(); + return; + } +} \ No newline at end of file diff --git a/engine/Autoloader.class.php b/engine/Autoloader.class.php new file mode 100755 index 0000000..12de692 --- /dev/null +++ b/engine/Autoloader.class.php @@ -0,0 +1,26 @@ + $value) { + $html = preg_replace($value['reg'], $value['replace'], $html); + } + echo $html; + } +} +function cdnFlush(){ + Cdn::flush(); +} +register_shutdown_function( 'cdnFlush' ); \ No newline at end of file diff --git a/engine/lib/Db.class.php b/engine/lib/Db.class.php new file mode 100644 index 0000000..cf7c00a --- /dev/null +++ b/engine/lib/Db.class.php @@ -0,0 +1,444 @@ +mysql = new Mysql( $master ); + if( isset( $slave ) && $slave ){ + $this->mysql->setSlave( $slave ); + } + } + public function __set( $key , $value ){ + if( $key == 'do_replication' ){ + $this->mysql->$key = $value; + return true; + } + } + public function __get( $key ){ + if( $key == 'sql' ){ + return $this->getSql(); + } + } + public function escape( $str ){ + return $this->mysql->escape( $str ); + } + private function getSql(){ + if( $this->ar_from ){ + $this->ar_sql = $this->_compile_select(); + $this->_resetCache(); + } + if( $this->ar_sql ){ + return $this->ar_sql; + }else{ + die('can not make sql...'); + } + } + public function getData( $sql = NULL , $key = NULL ){ + if( $sql == NULL ){ + $sql = $this->getSql(); + }else{ + $this->_resetCache(); + $this->ar_sql = $sql; + } + return $this->mysql->getData($sql , $key ); + } + public function getLine( $sql = NULL ){ + if( $sql == NULL ){ + $sql = $this->getSql(); + }else{ + $this->_resetCache(); + $this->ar_sql = $sql; + } + return $this->mysql->getLine($sql); + } + public function getVar( $sql = NULL ){ + if( $sql == NULL ){ + $sql = $this->getSql(); + }else{ + $this->_resetCache(); + $this->ar_sql = $sql; + } + return $this->mysql->getVar($sql); + } + public function runSql( $sql = NULL ){ + if( $sql == NULL ){ + $sql = $this->getSql(); + }else{ + $this->_resetCache(); + $this->ar_sql = $sql; + } + return $this->mysql->runSql($sql); + } + public function lastId(){ + return $this->mysql->lastId(); + } + public function error(){ + return $this->mysql->error(); + } + public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE){ + if ($table == ''){ + if ( ! isset($this->ar_from[0])){ + die('can not delete error no params...'); + } + + $table = $this->ar_from[0]; + }elseif (is_array($table)){ + foreach ($table as $single_table){ + $this->delete($single_table, $where, $limit, FALSE); + } + $this->_resetCache(); + return; + } + if ($where != ''){ + $this->where($where); + } + if ($limit != NULL){ + $this->limit($limit); + } + if (count($this->ar_where) == 0 && count($this->ar_like) == 0){ + die('db_del_must_use_where...'); + } + $sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit); + + if ($reset_data){ + $this->ar_sql = $sql; + $this->_resetCache(); + } + return $this->runSql($sql); + } + public function replace($table = '', $set = NULL){ + if ( ! is_null($set)){ + $this->set($set); + } + if (count($this->ar_set) == 0){ + die('can not replace error no params...'); + } + if ($table == ''){ + if ( ! isset($this->ar_from[0])){ + die('can not replace error no table to use...'); + } + $table = $this->ar_from[0]; + } + $sql = $this->_replace($table, array_keys($this->ar_set), array_values($this->ar_set)); + $this->ar_sql = $sql; + $this->_resetCache(); + return $this->runSql($sql); + } + public function update($table = '', $set = NULL, $where = NULL, $limit = NULL , $escape = true ){ + + if ( ! is_null($set)){ + $this->set($set); + } + + if (count($this->ar_set) == 0){ + die('can not update error no params...'); + } + + if ($table == ''){ + if ( ! isset($this->ar_from[0])){ + die('can not update error no table to use...'); + } + $table = $this->ar_from[0]; + } + if ($where != NULL){ + $this->where($where); + } + + if ($limit != NULL){ + $this->limit($limit); + } + if ( $escape && !preg_match("/(`)/i", trim($table))){ + $table = '`'.trim($table).'`'; + } + + $sql = $this->_update($table, $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit); + $this->ar_sql = $sql; + $this->_resetCache(); + return $this->runSql($sql); + } + public function insert($table = '', $set = NULL){ + if ( ! is_null($set)){ + $this->set($set); + } + if (count($this->ar_set) == 0){ + die('can not insert error no params...'); + } + if ($table == ''){ + if ( ! isset($this->ar_from[0])){ + die('can not insert error no table to use...'); + } + $table = $this->ar_from[0]; + } + $sql = $this->_insert($table, array_keys($this->ar_set), array_values($this->ar_set)); + $this->ar_sql = $sql; + $this->_resetCache(); + return $this->runSql($sql); + } + public function select($select = '*'){ + if (is_string($select)){ + $select = explode(',', $select); + } + foreach ($select as $val){ + $val = trim($val); + if ($val != ''){ + $this->ar_select[] = $val; + + } + } + return $this; + } + public function from($from , $escape = true ){ + foreach ((array)$from as $val){ + if (strpos($val, ',') !== FALSE){ + foreach (explode(',', $val) as $v){ + $v = trim($v); + if ($escape && !preg_match("/(`)/i", $v )){ + $v = '`'.trim($v).'`'; + } + $this->ar_from[] = $v; + } + }else{ + $val = trim($val); + if ($escape && !preg_match("/(`)/i", $val )){ + $val = '`'.trim($val).'`'; + } + $this->ar_from[] = $val; + } + } + + return $this; + } + function like($field, $match = ''){ + return $this->_like($field, $match, 'AND '); + } + function notLike($field, $match = '', $side = 'both'){ + return $this->_like($field, $match, 'AND ', 'NOT'); + } + function orLike($field, $match = ''){ + return $this->_like($field, $match, 'OR '); + } + function orNotLike($field, $match = ''){ + return $this->_like($field, $match, 'OR ', 'NOT'); + } + public function where($key, $value = NULL){ + return $this->_where($key, $value, 'AND '); + } + public function orWhere($key, $value = NULL, $escape = TRUE){ + return $this->_where($key, $value, 'OR ', $escape); + } + public function orderBy($orderby, $direction = '' , $escape = true ){ + if (trim($direction) != ''){ + $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC'; + } + if ( $escape && strpos($orderby, ',') !== FALSE){ + $temp = array(); + foreach (explode(',', $orderby) as $part) + { + $part = trim($part); + $temp[] = '`'.$part.'`'; + } + $orderby = implode(', ', $temp); + }elseif($escape == true ){ + $orderby ='`'.$orderby.'`'; + } + $orderby_statement = $orderby.$direction; + $this->ar_orderby[] = $orderby_statement; + return $this; + } + public function limit($value , $offset = NULL){ + $this->ar_limit = $value; + if ($offset != ''){ + $this->ar_offset = $offset; + } + return $this; + } + public function set($key, $value = NULL , $escape = true ){ + if ( ! is_array($key)){ + if(is_null($value) && $this->_has_operator($key) ){ + $key = array( $key ); + }else{ + $key = array($key => $value); + } + } + foreach ($key as $k => $v){ + if( is_numeric($k) && strpos( $v , '=' ) !== false ){ + list( $k , $v ) = explode( '=' , $v , 2 ); + $k = trim($k); + $v = trim($v); + if( $escape ){ + if ( !preg_match("/(`)/i", trim($k))){ + $k = '`'.trim($k).'`'; + } + if ( !preg_match("/(\-|\+)/i", $v)){ + $v = '`'.trim($v).'`'; + } + } + + }else{ + if ( $escape ){ + $k = '`'.$k.'`'; + $v = "'".$this->escape($v)."'"; + } + } + + $this->ar_set[$k] = $v; + } + return $this; + } + private function _resetCache(){ + $this->ar_select = array(); + $this->ar_from = array(); + $this->ar_where = array(); + $this->ar_like = array(); + $this->ar_offset = FALSE; + $this->ar_limit = FALSE; + $this->ar_orderby = array(); + $this->ar_set = array(); + } + private function _like($field, $match = '', $type = 'AND ', $not = ''){ + if ( ! is_array($field)){ + $field = array($field => $match); + } + foreach ($field as $k => $v){ + $prefix = (count($this->ar_like) == 0) ? '' : $type; + $v = $this->escape($v); + $like_statement = $prefix." `$k` $not LIKE '%{$v}%'"; + $this->ar_like[] = $like_statement; + + } + return $this; + } + private function _where($key, $value = NULL, $type = 'AND ', $escape = NULL){ + if ( ! is_array($key)){ + $key = array($key => $value); + } + + // If the escape value was not set will will base it on the global setting + if ( ! is_bool($escape)){ + //$escape = $this->_protect_identifiers; + } + + foreach ($key as $k => $v){ + $prefix = (count($this->ar_where) == 0 ) ? '' : $type; + if( !is_numeric($k) ){ + + if (is_null($v) && ! $this->_has_operator($k)){ + // value appears not to have been set, assign the test to IS NULL + $k = '`'.$k.'`'.' IS NULL'; + //$v = "'".$this->escape($v)."'"; + } + + if ( ! is_null($v)){ + if ( ! $this->_has_operator($k)){ + $k = '`'.$k.'` ='; + } + $v = "'".$this->escape($v)."'"; + } + }else{ + $k = NULL; + } + $this->ar_where[] = $prefix.$k.$v; + + + } + + return $this; + } + private function _has_operator($str){ + $str = trim($str); + if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str)){ + return FALSE; + } + return TRUE; + } + private function _compile_select(){ + + $sql = 'SELECT ' ; + + if (count($this->ar_select) == 0){ + $sql .= '*'; + }else{ + $sql .= implode(', ', $this->ar_select); + } + + if (count($this->ar_from) > 0){ + $sql .= "\nFROM "; + $sql .= implode("\n", $this->ar_from); + } + if (count($this->ar_where) > 0 OR count($this->ar_like) > 0){ + $sql .= "\n"; + $sql .= "WHERE "; + } + $sql .= implode("\n", $this->ar_where); + if (count($this->ar_like) > 0){ + if (count($this->ar_where) > 0){ + $sql .= "\nAND "; + } + $sql .= implode("\n", $this->ar_like); + } + if (count($this->ar_orderby) > 0){ + $sql .= "\nORDER BY "; + $sql .= implode(', ', $this->ar_orderby); + } + if (is_numeric($this->ar_limit)){ + $sql .= "\nLIMIT "; + $sql .= $this->ar_limit; + if( intval( $this->ar_offset ) ){ + $sql .= ','.intval( $this->ar_offset ); + } + } + return $sql; + } + private function _insert($table , $keys , $values ){ + $sql = "INSERT INTO $table (".join(',',$keys).")VALUES(".join(",",$values).")"; + return $sql; + } + private function _update($table, $values, $where, $orderby = array(), $limit = FALSE){ + foreach ($values as $key => $val){ + $valstr[] = $key . ' = ' . $val; + } + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + $sql .= $orderby.$limit; + + return $sql; + } + private function _replace($table, $keys, $values){ + return "REPLACE INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + private function _delete($table, $where = array(), $like = array(), $limit = FALSE){ + $conditions = ''; + if (count($where) > 0 OR count($like) > 0){ + $conditions = "\nWHERE "; + $conditions .= implode("\n", $where); + if (count($like) > 0){ + $conditions .= " AND "; + $conditions .= implode("\n", $like); + } + } + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } +} \ No newline at end of file diff --git a/engine/lib/IFCookie.class.php b/engine/lib/IFCookie.class.php new file mode 100644 index 0000000..1acc05c --- /dev/null +++ b/engine/lib/IFCookie.class.php @@ -0,0 +1,19 @@ +getImgSize(); + //print_r( $this->img_info ); + if( !$this->img_info ) return false; + $this->getNewSize(); + $this->makeIcon(); + } + function getImgSize(){ + $this->img_info = @getImagesize( $this->path ); + $this->w = $this->img_info[0]; + $this->h = $this->img_info[1]; + + switch ( $this->img_info[2] ){ + case 1: + $this->t = 'gif'; + break; + case 2: + $this->t = 'jpg'; + break; + case 3: + $this->t = 'png'; + break; + } + } + + function getNewSize(){ + if( $this->w > $this->h ){ + $this->nh = $this->size; + $this->nw = ($this->size/$this->h) * $this->w; + $this->type = 1; + }else{ + $this->nw = $this->size; + $this->nh = ($this->size/$this->w) * $this->h; + $this->type = 0; + } + } + + function makeIcon(){ + $type = $this->type; + //$img_des = ImageCreateTrueColor ( $this->size, $this->size ); + $img_des = ImageCreateTrueColor ( $this->size , $this->size ); + + $background = imagecolorallocate( $img_des , 255 , 255 , 255 ); + imagefill( $img_des , 0 , 0 , $background ); + + switch ( $this->t ){ + case 'gif': + $img_src = ImageCreateFromGIF ( $this->path ); + break; + + case 'jpg': + $img_src = ImageCreateFromJPEG ( $this->path ); + break; + + case 'png': + $img_src = ImageCreateFromPNG ( $this->path ); + break; + } + if( $type === 1 ){ + imagecopyresampled( $img_des, $img_src, 0, 0, ($this->w-$this->h)/2 , 0, $this->nw , $this->nh, $this->w, $this->h ); + }elseif( $type === 0 ){ + imagecopyresampled( $img_des, $img_src, 0, 0, 0 , ($this->h-$this->w)/2, $this->nw , $this->nh, $this->w, $this->h ); + }else{ + imagecopyresampled( $img_des, $img_src, 0, 0, 0 , 0 , $this->size, $this->size , $this->w, $this->h ); + } + + imageline( $img_des , 0 , 0 , 0 , ($this->size-1) , imagecolorallocate( $img_des , 220 , 220 , 220 ) ); + imageline( $img_des , 0 , ($this->size-1) , ($this->size-1) , ($this->size-1) , imagecolorallocate( $img_des , 220 , 220 , 220 ) ); + imageline( $img_des , ($this->size-1) , ($this->size-1) , ($this->size-1) , 0 , imagecolorallocate( $img_des , 220 , 220 , 220 ) ); + imageline( $img_des , ($this->size-1) , 0 , 0 , 0 , imagecolorallocate( $img_des , 220 , 220 , 220 ) ); + + //echo $this->dest ; + + switch ( $this->t ){ + case 'gif': + if ( empty( $this->dest ) ){ + header( "Content-type: image/gif" ); + return ImageGIF( $img_des ); + }else{ + return ImageGIF( $img_des, $this->dest ); + } + break; + + case 'jpg': + if ( empty( $this->dest ) ){ + header ( "Content-type: image/jpeg" ); + return ImageJPEG( $img_des ); + }else{ + return ImageJPEG( $img_des, $this->dest ); + } + break; + + case 'png': + if ( empty( $this->dest ) ){ + header ( "Content-type: image/png" ); + return ImagePNG( $img_des ); + }else{ + return ImagePNG( $img_des, $this->dest ); + } + break; + } + } + + + +} +/* +$icon = new Icon(); +$icon->path = 'a.gif'; +$icon->size = 64; +$icon->dest = 'b.gif'; +$icon->createIcon(); +*/ +?> \ No newline at end of file diff --git a/engine/lib/Lock.class.php b/engine/lib/Lock.class.php new file mode 100755 index 0000000..1207c5e --- /dev/null +++ b/engine/lib/Lock.class.php @@ -0,0 +1,51 @@ + 0 ){ + if( memcache_add( self::$memcache , $key , 'Locking' ,false , self::LOCKTIME ) ){ + self::$locked[$key] = 1; + return; + }else{ + $time--; + sleep(1); + } + } + } + } + public static function del( $key ){ + if( self::$locked[$key] ){ + self::init(); + if( self::$memcache !== false ){ + if( memcache_delete( self::$memcache , $key ) ){ + unset( self::$locked[$key] ); + return true; + } + } + } + + } + public static function delAll(){ + if( self::$locked && self::$memcache ){ + foreach( self::$locked as $k => $v ){ + if( memcache_delete( self::$memcache , $k ) ){ + unset( self::$locked[$k] ); + } + } + } + } +} +function autounLock(){ + Lock::delAll(); +} +register_shutdown_function( 'autounLock' ); \ No newline at end of file diff --git a/engine/lib/Mysql.class.php b/engine/lib/Mysql.class.php new file mode 100644 index 0000000..d35a48e --- /dev/null +++ b/engine/lib/Mysql.class.php @@ -0,0 +1,137 @@ +master = $master; + } + private function connect( $is_master = true ){ + if( $is_master ) $dbInfo = $this->master; + else $dbInfo = $this->slave; + if( !$db = mysql_connect( $dbInfo['host'] , $dbInfo['user'] , $dbInfo['passwd'] ) ){ + die('can\'t connect to mysql ' . $ $dbInfo['host'] ); + }else{ + // mysql_query( "set names 'utf8'" , $db ); + mysql_query( "set names 'utf8mb4'" , $db ); + } + //echo 'connect to: '. $dbInfo['host'].'at db:'.$dbInfo['dbname'].'
'; + mysql_select_db( $dbInfo['dbname'] , $db ); + + return $db; + } + private function dbRead(){ + if( isset( $this->dbRead ) ){ + mysql_ping( $this->dbRead ); + return $this->dbRead; + }else{ + if( !$this->do_replication ) return $this->dbWrite(); + else { + $this->dbRead = $this->connect( false ); + return $this->dbRead; + } + } + } + + private function dbWrite(){ + if( isset( $this->dbWrite ) ){ + mysql_ping( $this->dbWrite ); + return $this->dbWrite; + }else{ + $this->dbWrite = $this->connect( true ); + return $this->dbWrite; + } + } + public function setSlave( $slave ){ + + $this->slave['host'] = $slave['host']; + $this->slave['user'] = isset($slave['user']) ? $slave['user'] : $this->master['user']; + $this->slave['passwd'] = isset($slave['passwd']) ? $slave['passwd'] : $this->master['passwd']; + $this->slave['dbname'] = isset($slave['dbname']) ? $slave['dbname'] : $this->master['dbname']; + $this->do_replication = true; + } + public function saveError() { + //$GLOBALS['MYSQL_LAST_ERROR'] = mysql_error(); + //$GLOBALS['MYSQL_LAST_ERRNO'] = mysql_errno(); + if( mysql_errno() ){ + print_r( mysql_error() ); + } + + } + + public function runSql( $sql ) { + $ret = mysql_query( $sql , $this->dbWrite() ); + $this->saveError(); + return $ret; + } + public function getData( $sql , $key = NULL ){ + $GLOBALS['MYSQL_LAST_SQL'] = $sql; + $data = Array(); + $i = 0; + $result = mysql_query( $sql , $this->do_replication ? $this->dbRead() : $this->dbWrite() ); + + $this->saveError(); + + while( $Array = mysql_fetch_array($result, MYSQL_ASSOC ) ){ + if( $key && isset( $Array[$key] ) ){ + $data[$Array[$key]] = $Array; + }else{ + $data[$i++] = $Array; + } + } + + /* + if( mysql_errno() != 0 ) + echo mysql_error() .' ' . $sql; + */ + + mysql_free_result($result); + + if( count( $data ) > 0 ) + return $data; + else + return false; + } + + public function getLine( $sql ){ + $data = $this->getData( $sql ); + return @reset($data); + } + + public function getVar( $sql ){ + $data = $this->getLine( $sql ); + return $data[ @reset(@array_keys( $data )) ]; + } + + public function lastId(){ + $result = mysql_query( "SELECT LAST_INSERT_ID()" , $this->dbWrite() ); + return reset( mysql_fetch_array( $result, MYSQL_ASSOC ) ); + } + + public function closeDb(){ + if( isset( $this->dbRead ) ){ + @mysql_close( $this->dbRead ); + unset( $this->dbRead ); + } + if( isset( $this->dbWrite ) ){ + @mysql_close( $this->dbWrite ); + unset( $this->dbWrite ); + } + } + + public function escape( $str ){ + if( isset($this->dbRead)) $db = $this->dbRead ; + elseif( isset($this->dbWrite) ) $db = $this->dbWrite; + else $db = $this->dbRead(); + + return mysql_real_escape_string( $str , $db ); + } + + public function errno(){ + return $GLOBALS['MYSQL_LAST_ERRNO']; + } + + public function error(){ + return $GLOBALS['MYSQL_LAST_ERROR']; + } +} \ No newline at end of file diff --git a/engine/lib/SafeHtml.class.php b/engine/lib/SafeHtml.class.php new file mode 100755 index 0000000..7f86bd2 --- /dev/null +++ b/engine/lib/SafeHtml.class.php @@ -0,0 +1,676 @@ + + * @copyright 2004-2005 Roman Ivanov + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version CVS: $Id:$ + * @link http://pear.php.net/package/HTML_Safe + */ + + +/** + * This package requires HTMLSax3 package + */ +require_once __DIR__.'/XML/HTMLSax3.php'; + + +/** + * + * HTML_Safe Parser + * + * This parser strips down all potentially dangerous content within HTML: + * + * It also tries to convert code to XHTML valid, but htmltidy is far better + * solution for this task. + * + * Example: + *
+ * $parser =new HTML_Safe();
+ * $result = $parser->parse($doc);
+ * 
+ * + * @category HTML + * @package HTML_Safe + * @author Roman Ivanov + * @copyright 1997-2005 Roman Ivanov + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version Release: @package_version@ + * @link http://pear.php.net/package/HTML_Safe + */ +class SafeHtml +{ + /** + * Storage for resulting HTML output + * + * @var string + * @access private + */ + var $_xhtml = ''; + + /** + * Array of counters for each tag + * + * @var array + * @access private + */ + var $_counter = array(); + + /** + * Stack of unclosed tags + * + * @var array + * @access private + */ + var $_stack = array(); + + /** + * Array of counters for tags that must be deleted with all content + * + * @var array + * @access private + */ + var $_dcCounter = array(); + + /** + * Stack of unclosed tags that must be deleted with all content + * + * @var array + * @access private + */ + var $_dcStack = array(); + + /** + * Stores level of list (ol/ul) nesting + * + * @var int + * @access private + */ + var $_listScope = 0; + + /** + * Stack of unclosed list tags + * + * @var array + * @access private + */ + var $_liStack = array(); + + /** + * Array of prepared regular expressions for protocols (schemas) matching + * + * @var array + * @access private + */ + var $_protoRegexps = array(); + + /** + * Array of prepared regular expressions for CSS matching + * + * @var array + * @access private + */ + var $_cssRegexps = array(); + + /** + * List of single tags ("") + * + * @var array + * @access public + */ + var $singleTags = array('area', 'br', 'img', 'input', 'hr', 'wbr', ); + + /** + * List of dangerous tags (such tags will be deleted) + * + * @var array + * @access public + */ + var $deleteTags = array( + 'applet', 'base', 'basefont', 'bgsound', 'blink', 'body', + 'embed', 'frame', 'frameset', 'head', 'html', 'ilayer', + 'iframe', 'layer', 'link', 'meta', 'object', 'style', + 'title', 'script', + ); + + /** + * List of dangerous tags (such tags will be deleted, and all content + * inside this tags will be also removed) + * + * @var array + * @access public + */ + var $deleteTagsContent = array('script', 'style', 'title', 'xml', ); + + /** + * Type of protocols filtering ('white' or 'black') + * + * @var string + * @access public + */ + var $protocolFiltering = 'white'; + + /** + * List of "dangerous" protocols (used for blacklist-filtering) + * + * @var array + * @access public + */ + var $blackProtocols = array( + 'about', 'chrome', 'data', 'disk', 'hcp', + 'help', 'javascript', 'livescript', 'lynxcgi', 'lynxexec', + 'ms-help', 'ms-its', 'mhtml', 'mocha', 'opera', + 'res', 'resource', 'shell', 'vbscript', 'view-source', + 'vnd.ms.radio', 'wysiwyg', + ); + + /** + * List of "safe" protocols (used for whitelist-filtering) + * + * @var array + * @access public + */ + var $whiteProtocols = array( + 'ed2k', 'file', 'ftp', 'gopher', 'http', 'https', + 'irc', 'mailto', 'news', 'nntp', 'telnet', 'webcal', + 'xmpp', 'callto', + ); + + /** + * List of attributes that can contain protocols + * + * @var array + * @access public + */ + var $protocolAttributes = array( + 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src', + ); + + /** + * List of dangerous CSS keywords + * + * Whole style="" attribute will be removed, if parser will find one of + * these keywords + * + * @var array + * @access public + */ + var $cssKeywords = array( + 'absolute', 'behavior', 'behaviour', 'content', 'expression', + 'fixed', 'include-source', 'moz-binding', + ); + + /** + * List of tags that can have no "closing tag" + * + * @var array + * @access public + * @deprecated XHTML does not allow such tags + */ + var $noClose = array(); + + /** + * List of block-level tags that terminates paragraph + * + * Paragraph will be closed when this tags opened + * + * @var array + * @access public + */ + var $closeParagraph = array( + 'address', 'blockquote', 'center', 'dd', 'dir', 'div', + 'dl', 'dt', 'h1', 'h2', 'h3', 'h4', + 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee', + 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre', + 'table', 'ul', 'xmp', + ); + + /** + * List of table tags, all table tags outside a table will be removed + * + * @var array + * @access public + */ + var $tableTags = array( + 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', + 'thead', 'tr', + ); + + /** + * List of list tags + * + * @var array + * @access public + */ + var $listTags = array('dir', 'menu', 'ol', 'ul', 'dl', ); + + /** + * List of dangerous attributes + * + * @var array + * @access public + */ + var $attributes = array('dynsrc', 'name', ); + /** + * List of delete attributes + * + * @var array + * @access public + */ + var $deleteAttrs = array( 'id', 'class', 'urltoajax', 'action-data', 'action-type', 'confirm', 'hovertip', 'textcount',); + /** + * List of allowed "namespaced" attributes + * + * @var array + * @access public + */ + var $attributesNS = array('xml:lang', ); + + /** + * Constructs class + * + * @access public + */ + function HTML_Safe() + { + //making regular expressions based on Proto & CSS arrays + foreach ($this->blackProtocols as $proto) { + $preg = "/[\s\x01-\x1F]*"; + for ($i=0; $i_protoRegexps[] = $preg; + } + + foreach ($this->cssKeywords as $css) { + $this->_cssRegexps[] = '/' . $css . '/i'; + } + return true; + } + + /** + * Handles the writing of attributes - called from $this->_openHandler() + * + * @param array $attrs array of attributes $name => $value + * @return boolean + * @access private + */ + function _writeAttrs ($attrs) + { + if (is_array($attrs) ) { + foreach ($attrs as $name => $value) { + $name = strtolower($name); + if(in_array( $name , $this->deleteAttrs )){ + continue; + } + if (strpos($name, 'on') === 0) { + continue; + } + if (strpos($name, 'data') === 0) { + continue; + } + if (in_array($name, $this->attributes)) { + continue; + } + if (!preg_match("/^[a-z0-9]+$/i", $name)) { + if (!in_array($name, $this->attributesNS)) { + continue; + } + } + + if (($value === TRUE) || (is_null($value))) { + $value = $name; + } + + if ($name == 'style') { + + // removes insignificant backslahes + $value = str_replace("\\", '', $value); + + // removes CSS comments + while (1) + { + $_value = preg_replace("!/\*.*?\*/!s", '', $value); + if ($_value == $value) break; + $value = $_value; + } + + // replace all & to & + $value = str_replace('&', '&', $value); + $value = str_replace('&', '&', $value); + + foreach ($this->_cssRegexps as $css) { + if (preg_match($css, $value)) { + continue 2; + } + } + foreach ($this->_protoRegexps as $proto) { + if (preg_match($proto, $value)) { + continue 2; + } + } + } + + $tempval = preg_replace('/&#(\d+);?/me', "chr('\\1')", $value); //"' + $tempval = preg_replace('/&#x([0-9a-f]+);?/mei', "chr(hexdec('\\1'))", $tempval); + + if ((in_array($name, $this->protocolAttributes)) && + (strpos($tempval, ':') !== false)) + { + if ($this->protocolFiltering == 'black') { + foreach ($this->_protoRegexps as $proto) { + if (preg_match($proto, $tempval)) continue 2; + } + } else { + $_tempval = explode(':', $tempval); + $proto = $_tempval[0]; + if (!in_array($proto, $this->whiteProtocols)) { + continue; + } + } + } + + $value = str_replace("\"", """, $value); + $this->_xhtml .= ' ' . $name . '="' . $value . '"'; + } + } + return true; + } + + /** + * Opening tag handler - called from HTMLSax + * + * @param object $parser HTML Parser + * @param string $name tag name + * @param array $attrs tag attributes + * @return boolean + * @access private + */ + function _openHandler(&$parser, $name, $attrs) + { + $name = strtolower($name); + + if (in_array($name, $this->deleteTagsContent)) { + array_push($this->_dcStack, $name); + $this->_dcCounter[$name] = isset($this->_dcCounter[$name]) ? $this->_dcCounter[$name]+1 : 1; + } + if (count($this->_dcStack) != 0) { + return true; + } + + if (in_array($name, $this->deleteTags)) { + return true; + } + + if (!preg_match("/^[a-z0-9]+$/i", $name)) { + if (preg_match("!(?:\@|://)!i", $name)) { + $this->_xhtml .= '<' . $name . '>'; + } + return true; + } + + if (in_array($name, $this->singleTags)) { + $this->_xhtml .= '<' . $name; + $this->_writeAttrs($attrs); + $this->_xhtml .= ' />'; + return true; + } + + // TABLES: cannot open table elements when we are not inside table + if ((isset($this->_counter['table'])) && ($this->_counter['table'] <= 0) + && (in_array($name, $this->tableTags))) + { + return true; + } + + // PARAGRAPHS: close paragraph when closeParagraph tags opening + if ((in_array($name, $this->closeParagraph)) && (in_array('p', $this->_stack))) { + $this->_closeHandler($parser, 'p'); + } + + // LISTS: we should close
  • if
  • of the same level opening + if ($name == 'li' && count($this->_liStack) && + $this->_listScope == $this->_liStack[count($this->_liStack)-1]) + { + $this->_closeHandler($parser, 'li'); + } + + // LISTS: we want to know on what nesting level of lists we are + if (in_array($name, $this->listTags)) { + $this->_listScope++; + } + if ($name == 'li') { + array_push($this->_liStack, $this->_listScope); + } + + $this->_xhtml .= '<' . $name; + $this->_writeAttrs($attrs); + $this->_xhtml .= '>'; + array_push($this->_stack,$name); + $this->_counter[$name] = isset($this->_counter[$name]) ? $this->_counter[$name]+1 : 1; + return true; + } + + /** + * Closing tag handler - called from HTMLSax + * + * @param object $parsers HTML parser + * @param string $name tag name + * @return boolean + * @access private + */ + function _closeHandler(&$parser, $name) + { + + $name = strtolower($name); + + if (isset($this->_dcCounter[$name]) && ($this->_dcCounter[$name] > 0) && + (in_array($name, $this->deleteTagsContent))) + { + while ($name != ($tag = array_pop($this->_dcStack))) { + $this->_dcCounter[$tag]--; + } + + $this->_dcCounter[$name]--; + } + + if (count($this->_dcStack) != 0) { + return true; + } + + if ((isset($this->_counter[$name])) && ($this->_counter[$name] > 0)) { + while ($name != ($tag = array_pop($this->_stack))) { + $this->_closeTag($tag); + } + + $this->_closeTag($name); + } + return true; + } + + /** + * Closes tag + * + * @param string $tag tag name + * @return boolean + * @access private + */ + function _closeTag($tag) + { + if (!in_array($tag, $this->noClose)) { + $this->_xhtml .= ''; + } + + $this->_counter[$tag]--; + + if (in_array($tag, $this->listTags)) { + $this->_listScope--; + } + + if ($tag == 'li') { + array_pop($this->_liStack); + } + return true; + } + + /** + * Character data handler - called from HTMLSax + * + * @param object $parser HTML parser + * @param string $data textual data + * @return boolean + * @access private + */ + function _dataHandler(&$parser, $data) + { + if (count($this->_dcStack) == 0) { + $this->_xhtml .= $data; + } + return true; + } + + /** + * Escape handler - called from HTMLSax + * + * @param object $parser HTML parser + * @param string $data comments or other type of data + * @return boolean + * @access private + */ + function _escapeHandler(&$parser, $data) + { + return true; + } + + /** + * Returns the XHTML document + * + * @return string Processed (X)HTML document + * @access public + */ + function getXHTML () + { + while ($tag = array_pop($this->_stack)) { + $this->_closeTag($tag); + } + + return $this->_xhtml; + } + + /** + * Clears current document data + * + * @return boolean + * @access public + */ + function clear() + { + $this->_xhtml = ''; + return true; + } + + /** + * Main parsing fuction + * + * @param string $doc HTML document for processing + * @return string Processed (X)HTML document + * @access public + */ + function parse($doc) + { + + // Save all '<' symbols + $doc = preg_replace("/<(?=[^a-zA-Z\/\!\?\%])/", '<', $doc); + + // Web documents shouldn't contains \x00 symbol + $doc = str_replace("\x00", '', $doc); + + // Opera6 bug workaround + $doc = str_replace("\xC0\xBC", '<', $doc); + + // UTF-7 encoding ASCII decode + $doc = $this->repackUTF7($doc); + + // Instantiate the parser + $parser=new XML_HTMLSax3(); + + // Set up the parser + $parser->set_object($this); + + $parser->set_element_handler('_openHandler','_closeHandler'); + $parser->set_data_handler('_dataHandler'); + $parser->set_escape_handler('_escapeHandler'); + + $parser->parse($doc); + + return $this->getXHTML(); + + } + + + /** + * UTF-7 decoding fuction + * + * @param string $str HTML document for recode ASCII part of UTF-7 back to ASCII + * @return string Decoded document + * @access private + */ + function repackUTF7($str) + { + return preg_replace_callback('!\+([0-9a-zA-Z/]+)\-!', array($this, 'repackUTF7Callback'), $str); + } + + /** + * Additional UTF-7 decoding fuction + * + * @param string $str String for recode ASCII part of UTF-7 back to ASCII + * @return string Recoded string + * @access private + */ + function repackUTF7Callback($str) + { + $str = base64_decode($str[1]); + $str = preg_replace_callback('/^((?:\x00.)*)((?:[^\x00].)+)/', array($this, 'repackUTF7Back'), $str); + return preg_replace('/\x00(.)/', '$1', $str); + } + + /** + * Additional UTF-7 encoding fuction + * + * @param string $str String for recode ASCII part of UTF-7 back to ASCII + * @return string Recoded string + * @access private + */ + function repackUTF7Back($str) + { + return $str[1].'+'.rtrim(base64_encode($str[2]), '=').'-'; + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ + +?> diff --git a/engine/lib/Thumbnail.class.php b/engine/lib/Thumbnail.class.php new file mode 100755 index 0000000..ccf56a3 --- /dev/null +++ b/engine/lib/Thumbnail.class.php @@ -0,0 +1,167 @@ +setMaxSize( 200, 200 ); // Specify maximum size (width, height) +$myThumb->setImgSource( 'image_original.jpg' ); // Specify original image filename +$myThumb->Create( 'image_thumbnail.jpg' ); // Specify destination image filename or leave empty to output directly + +You can also get additional info about original image or thumbnail... + +$myThumb = new Thumbnail; // Start using a class +$myThumb->setImgSource( 'image_original.jpg' ); // Specify original image filename +$myThumb->getImageData( 'width' ) // This will get you pixel width of original image. getImageData arguments are width|height|type + +You can also use getThumbData to see the size of thumbnail that will be created. +$myThumb = new Thumbnail; // Start using a class +$myThumb->setMaxSize( 200, 200 ); // Specify maximum size (width, height) +$myThumb->getThumbData( 'width' ) // This will get you pixel width of thumbnail image. getImageData arguments are width|height|type + + +*/ + + +class Thumbnail +{ + + // Set destination filename + function setImgSource( $source ) + { + $this->source = $source; + } + + // Set maximum size of thumbnail + function setMaxSize ( $max_width = 100, $max_height = 100 ) + { + $this->max_width = $max_width; + $this->max_height = $max_height; + } + + + // Get info about original image + function getImageData( $data ) + { + $size = getimagesize( $this->source ); + + switch ( $data ) + { + case 'width': + return $size[0]; + break; + case 'height': + return $size[1]; + break; + case 'type': + switch ( $size[2] ) + { + case 1: + return 'gif'; + break; + case 2: + return 'jpg'; + break; + case 3: + return 'png'; + break; + } + break; + } + } + + // Get info about thumbnail + function getThumbData( $data ){ + $w_ratio = $this->max_width / $this->GetImageData('width'); + $h_ratio = $this->max_height / $this->GetImageData('height'); + + if ( $h_ratio < $w_ratio ){ + $height = $this->max_height; + $width = round( $this->GetImageData('width') * $h_ratio, 0); + }else{ + $width = $this->max_width; + $height = round( $this->GetImageData('height') * $w_ratio, 0); + } + + switch ( $data ){ + case 'width': + return $width; + break; + case 'height': + return $height; + break; + } + } + + + // Creating a thumbnail + function Create( $dest = NULL ){ + $img_des = imagecreatetruecolor( $this->GetThumbData('width'), $this->GetThumbData('height') ); + + $background = imagecolorallocate( $img_des , 255 , 255 , 255 ); + imagefill( $img_des , 0 , 0 , $background ); + + switch ( $this->GetImageData('type') ){ + case 'gif': + $img_src = imagecreatefromgif( $this->source ); + break; + + case 'jpg': + $img_src = imagecreatefromjpeg( $this->source ); + break; + + case 'png': + $img_src = imagecreatefrompng( $this->source ); + break; + } + + // GD 1.0 + //ImageCopyResized( $img_des, $img_src, 0, 0, 0, 0, $this->GetThumbData('width'), $this->GetThumbData('height'), $this->GetImageData('width'), $this->GetImageData('height') ); + // GD 2.0 + imagecopyresampled( $img_des, $img_src, 0, 0, 0, 0, $this->GetThumbData('width'), $this->GetThumbData('height'), $this->GetImageData('width'), $this->GetImageData('height') ); + + switch ( $this->GetImageData('type') ){ + case 'gif': + if ( empty( $dest ) ){ + ob_start(); + //header( "Content-type: image/gif" ); + imagegif( $img_des ); + $return = ob_get_clean(); + return $return; + }else{ + return imagegif( $img_des, $dest ); + } + break; + + case 'jpg': + if ( empty( $dest ) ){ + ob_start(); + //header ( "Content-type: image/jpeg" ); + imagejpeg( $img_des ); + $return = ob_get_clean(); + return $return; + }else{ + return imagejpeg( $img_des, $dest ); + } + break; + + case 'png': + if ( empty( $dest ) ){ + ob_start(); + //header ( "Content-type: image/png" ); + imagepng( $img_des ); + $return = ob_get_clean(); + return $return; + }else{ + return imagepng( $img_des, $dest ); + } + break; + } + } +} +?> \ No newline at end of file diff --git a/engine/lib/Url.class.php b/engine/lib/Url.class.php new file mode 100755 index 0000000..c064376 --- /dev/null +++ b/engine/lib/Url.class.php @@ -0,0 +1,147 @@ + $v ){ + if( $v ){ + $url .= $k.'/'.$v.'/'; + } + } + } + }else{ + if( $base ) + $custom += $base; + + if( $custom ) + $url .= '?'.http_build_query($custom); + } + + return $url; + } + public static function initParams(){ + if( !self::$enter ){ + $custom = array(); + if( !self::$url ){ + if( c('static_url') ){ + self::$url = isset($_SERVER['REDIRECT_URL'])&&$_SERVER['REDIRECT_URL']?$_SERVER['REDIRECT_URL']:$_SERVER['PATH_INFO']; + }else{ + self::$url = $_GET; + } + } + if( c('static_url') ){ + $tempArray = explode( '/' , trim(self::$url , '/' ) ); + if( $tempArray ){ + if( count( $tempArray )%2 == 0 ){ + $custom['class'] = safeUrlString(array_shift( $tempArray )); + $custom['method'] = safeUrlString(array_shift( $tempArray )); + }else{ + $custom['class'] = safeUrlString(array_shift( $tempArray )); + $custom['method'] = c('default_method'); + } + } + if( $tempArray ){ + foreach( array_chunk($tempArray, 2) as $v ){ + list( $key , $value ) = $v; + $custom[$key] = $value; + } + } + }else{ + $custom = self::$url; + } + $base = array(); + self::formatUrlParams( $base , $custom ); + self::$enter['class'] = $base[self::SHORT_CLASS_TAG]?:c('default_class'); + self::$enter['method'] = $base[self::SHORT_METHOD_TAG]?:c('default_method'); + self::$params = $custom; + if( c('static_url') ){ + $_REQUEST += $base + $custom; + $_GET += $base + $custom; + } + } + } + private static function formatUrlParams( &$base , &$custom , $old = array() ){ + // init url params + if( !is_array( $custom ) ){ + parse_str( ltrim( $custom , '?' ) , $custom); + } + $custom += self::$custom; + if( $old ){ + foreach( $old as $v ){ + if( $v && self::$params[$v] ){ + $custom[$v] = self::$params[$v]; + } + } + } + //init custom params + $needFix = array( 'class' , 'method' , self::SHORT_CLASS_TAG , self::SHORT_CLASS_TAG ); + foreach( $needFix as $v ){ + $custom[$v] = $custom[$v]?:NULL; + } + + $class = $custom[self::SHORT_CLASS_TAG]?:$custom['class']; + $method = $custom[self::SHORT_METHOD_TAG]?:$custom['method']; + unset( $custom['class'], $custom[self::SHORT_CLASS_TAG] , $custom['method'] ,$custom[self::SHORT_METHOD_TAG] ); + $base[self::SHORT_CLASS_TAG] = $class; + $base[self::SHORT_METHOD_TAG] = $method; + } +} \ No newline at end of file diff --git a/engine/lib/Weibo.class.php b/engine/lib/Weibo.class.php new file mode 100755 index 0000000..a9e375e --- /dev/null +++ b/engine/lib/Weibo.class.php @@ -0,0 +1,64 @@ +set_remote_ip( self::$ip ); + } + } + } + private static function initWeiboOAuth(){ + if( !self::$weiboOAuth ){ + include_once( "saetv2.ex.class.php" ); + self::$weiboOAuth = new SaeTOAuthV2( self::$akey, self::$skey, self::$access_token, self::$refresh_token ); + if( self::$ip ){ + self::$weiboOAuth->remote_ip = self::$ip; + } + } + } +} \ No newline at end of file diff --git a/engine/lib/XML/HTMLSax3.php b/engine/lib/XML/HTMLSax3.php new file mode 100644 index 0000000..25d12a7 --- /dev/null +++ b/engine/lib/XML/HTMLSax3.php @@ -0,0 +1,688 @@ + Original port from Python | +// | Authors: Harry Fuecks Port to PEAR + more | +// | Authors: Many @ Sitepointforums Advanced PHP Forums | +// +----------------------------------------------------------------------+ +// +// $Id: HTMLSax3.php,v 1.2 2007/10/29 21:41:34 hfuecks Exp $ +// +/** +* Main parser components +* @package XML_HTMLSax3 +* @version $Id: HTMLSax3.php,v 1.2 2007/10/29 21:41:34 hfuecks Exp $ +*/ +/** +* Required classes +*/ +define('XML_HTMLSAX3', 'XML/'); +if (!defined('XML_HTMLSAX3')) { + define('XML_HTMLSAX3', 'XML/'); +} +require_once(__DIR__ . '/HTMLSax3/States.php'); +require_once(__DIR__ . '/HTMLSax3/Decorators.php'); + +/** +* Base State Parser +* @package XML_HTMLSax3 +* @access protected +* @abstract +*/ +class XML_HTMLSax3_StateParser { + /** + * Instance of user front end class to be passed to callbacks + * @var XML_HTMLSax3 + * @access private + */ + var $htmlsax; + /** + * User defined object for handling elements + * @var object + * @access private + */ + var $handler_object_element; + /** + * User defined open tag handler method + * @var string + * @access private + */ + var $handler_method_opening; + /** + * User defined close tag handler method + * @var string + * @access private + */ + var $handler_method_closing; + /** + * User defined object for handling data in elements + * @var object + * @access private + */ + var $handler_object_data; + /** + * User defined data handler method + * @var string + * @access private + */ + var $handler_method_data; + /** + * User defined object for handling processing instructions + * @var object + * @access private + */ + var $handler_object_pi; + /** + * User defined processing instruction handler method + * @var string + * @access private + */ + var $handler_method_pi; + /** + * User defined object for handling JSP/ASP tags + * @var object + * @access private + */ + var $handler_object_jasp; + /** + * User defined JSP/ASP handler method + * @var string + * @access private + */ + var $handler_method_jasp; + /** + * User defined object for handling XML escapes + * @var object + * @access private + */ + var $handler_object_escape; + /** + * User defined XML escape handler method + * @var string + * @access private + */ + var $handler_method_escape; + /** + * User defined handler object or NullHandler + * @var object + * @access private + */ + var $handler_default; + /** + * Parser options determining parsing behavior + * @var array + * @access private + */ + var $parser_options = array(); + /** + * XML document being parsed + * @var string + * @access private + */ + var $rawtext; + /** + * Position in XML document relative to start (0) + * @var int + * @access private + */ + var $position; + /** + * Length of the XML document in characters + * @var int + * @access private + */ + var $length; + /** + * Array of state objects + * @var array + * @access private + */ + var $State = array(); + + /** + * Constructs XML_HTMLSax3_StateParser setting up states + * @var XML_HTMLSax3 instance of user front end class + * @access protected + */ + function XML_HTMLSax3_StateParser (& $htmlsax) { + $this->htmlsax = & $htmlsax; + $this->State[XML_HTMLSAX3_STATE_START] =new XML_HTMLSax3_StartingState(); + + $this->State[XML_HTMLSAX3_STATE_CLOSING_TAG] =new XML_HTMLSax3_ClosingTagState(); + $this->State[XML_HTMLSAX3_STATE_TAG] =new XML_HTMLSax3_TagState(); + $this->State[XML_HTMLSAX3_STATE_OPENING_TAG] =new XML_HTMLSax3_OpeningTagState(); + + $this->State[XML_HTMLSAX3_STATE_PI] =new XML_HTMLSax3_PiState(); + $this->State[XML_HTMLSAX3_STATE_JASP] =new XML_HTMLSax3_JaspState(); + $this->State[XML_HTMLSAX3_STATE_ESCAPE] =new XML_HTMLSax3_EscapeState(); + } + + /** + * Moves the position back one character + * @access protected + * @return void + */ + function unscanCharacter() { + $this->position -= 1; + } + + /** + * Moves the position forward one character + * @access protected + * @return void + */ + function ignoreCharacter() { + $this->position += 1; + } + + /** + * Returns the next character from the XML document or void if at end + * @access protected + * @return mixed + */ + function scanCharacter() { + if ($this->position < $this->length) { + return $this->rawtext{$this->position++}; + } + } + + /** + * Returns a string from the current position to the next occurance + * of the supplied string + * @param string string to search until + * @access protected + * @return string + */ + function scanUntilString($string) { + $start = $this->position; + $this->position = strpos($this->rawtext, $string, $start); + if ($this->position === FALSE) { + $this->position = $this->length; + } + return substr($this->rawtext, $start, $this->position - $start); + } + + /** + * Returns a string from the current position until the first instance of + * one of the characters in the supplied string argument + * @param string string to search until + * @access protected + * @return string + * @abstract + */ + function scanUntilCharacters($string) {} + + /** + * Moves the position forward past any whitespace characters + * @access protected + * @return void + * @abstract + */ + function ignoreWhitespace() {} + + /** + * Begins the parsing operation, setting up any decorators, depending on + * parse options invoking _parse() to execute parsing + * @param string XML document to parse + * @access protected + * @return void + */ + function parse($data) { + if ($this->parser_options['XML_OPTION_TRIM_DATA_NODES']==1) { + $decorator =new XML_HTMLSax3_Trim( + $this->handler_object_data, + $this->handler_method_data); + $this->handler_object_data =& $decorator; + $this->handler_method_data = 'trimData'; + } + if ($this->parser_options['XML_OPTION_CASE_FOLDING']==1) { + $open_decor =new XML_HTMLSax3_CaseFolding( + $this->handler_object_element, + $this->handler_method_opening, + $this->handler_method_closing); + $this->handler_object_element =& $open_decor; + $this->handler_method_opening ='foldOpen'; + $this->handler_method_closing ='foldClose'; + } + if ($this->parser_options['XML_OPTION_LINEFEED_BREAK']==1) { + $decorator =new XML_HTMLSax3_Linefeed( + $this->handler_object_data, + $this->handler_method_data); + $this->handler_object_data =& $decorator; + $this->handler_method_data = 'breakData'; + } + if ($this->parser_options['XML_OPTION_TAB_BREAK']==1) { + $decorator =new XML_HTMLSax3_Tab( + $this->handler_object_data, + $this->handler_method_data); + $this->handler_object_data =& $decorator; + $this->handler_method_data = 'breakData'; + } + if ($this->parser_options['XML_OPTION_ENTITIES_UNPARSED']==1) { + $decorator =new XML_HTMLSax3_Entities_Unparsed( + $this->handler_object_data, + $this->handler_method_data); + $this->handler_object_data =& $decorator; + $this->handler_method_data = 'breakData'; + } + if ($this->parser_options['XML_OPTION_ENTITIES_PARSED']==1) { + $decorator =new XML_HTMLSax3_Entities_Parsed( + $this->handler_object_data, + $this->handler_method_data); + $this->handler_object_data =& $decorator; + $this->handler_method_data = 'breakData'; + } + // Note switched on by default + if ($this->parser_options['XML_OPTION_STRIP_ESCAPES']==1) { + $decorator =new XML_HTMLSax3_Escape_Stripper( + $this->handler_object_escape, + $this->handler_method_escape); + $this->handler_object_escape =& $decorator; + $this->handler_method_escape = 'strip'; + } + $this->rawtext = $data; + $this->length = strlen($data); + $this->position = 0; + $this->_parse(); + } + + /** + * Performs the parsing itself, delegating calls to a specific parser + * state + * @param constant state object to parse with + * @access protected + * @return void + */ + function _parse($state = XML_HTMLSAX3_STATE_START) { + do { + $state = $this->State[$state]->parse($this); + } while ($state != XML_HTMLSAX3_STATE_STOP && + $this->position < $this->length); + } +} + +/** +* Parser for PHP Versions below 4.3.0. Uses a slower parsing mechanism than +* the equivalent PHP 4.3.0+ subclass of StateParser +* @package XML_HTMLSax3 +* @access protected +* @see XML_HTMLSax3_StateParser_Gtet430 +*/ +class XML_HTMLSax3_StateParser_Lt430 extends XML_HTMLSax3_StateParser { + /** + * Constructs XML_HTMLSax3_StateParser_Lt430 defining available + * parser options + * @var XML_HTMLSax3 instance of user front end class + * @access protected + */ + function XML_HTMLSax3_StateParser_Lt430(& $htmlsax) { + parent::XML_HTMLSax3_StateParser($htmlsax); + $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0; + $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0; + $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0; + $this->parser_options['XML_OPTION_TAB_BREAK'] = 0; + $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0; + $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0; + $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0; + } + + /** + * Returns a string from the current position until the first instance of + * one of the characters in the supplied string argument + * @param string string to search until + * @access protected + * @return string + */ + function scanUntilCharacters($string) { + $startpos = $this->position; + while ($this->position < $this->length && strpos($string, $this->rawtext{$this->position}) === FALSE) { + $this->position++; + } + return substr($this->rawtext, $startpos, $this->position - $startpos); + } + + /** + * Moves the position forward past any whitespace characters + * @access protected + * @return void + */ + function ignoreWhitespace() { + while ($this->position < $this->length && + strpos(" \n\r\t", $this->rawtext{$this->position}) !== FALSE) { + $this->position++; + } + } + + /** + * Begins the parsing operation, setting up the unparsed XML entities + * decorator if necessary then delegating further work to parent + * @param string XML document to parse + * @access protected + * @return void + */ + function parse($data) { + parent::parse($data); + } +} + +/** +* Parser for PHP Versions equal to or greater than 4.3.0. Uses a faster +* parsing mechanism than the equivalent PHP < 4.3.0 subclass of StateParser +* @package XML_HTMLSax3 +* @access protected +* @see XML_HTMLSax3_StateParser_Lt430 +*/ +class XML_HTMLSax3_StateParser_Gtet430 extends XML_HTMLSax3_StateParser { + /** + * Constructs XML_HTMLSax3_StateParser_Gtet430 defining available + * parser options + * @var XML_HTMLSax3 instance of user front end class + * @access protected + */ + function XML_HTMLSax3_StateParser_Gtet430(& $htmlsax) { + parent::XML_HTMLSax3_StateParser($htmlsax); + $this->parser_options['XML_OPTION_TRIM_DATA_NODES'] = 0; + $this->parser_options['XML_OPTION_CASE_FOLDING'] = 0; + $this->parser_options['XML_OPTION_LINEFEED_BREAK'] = 0; + $this->parser_options['XML_OPTION_TAB_BREAK'] = 0; + $this->parser_options['XML_OPTION_ENTITIES_PARSED'] = 0; + $this->parser_options['XML_OPTION_ENTITIES_UNPARSED'] = 0; + $this->parser_options['XML_OPTION_STRIP_ESCAPES'] = 0; + } + /** + * Returns a string from the current position until the first instance of + * one of the characters in the supplied string argument. + * @param string string to search until + * @access protected + * @return string + */ + function scanUntilCharacters($string) { + $startpos = $this->position; + $length = strcspn($this->rawtext, $string, $startpos); + $this->position += $length; + return substr($this->rawtext, $startpos, $length); + } + + /** + * Moves the position forward past any whitespace characters + * @access protected + * @return void + */ + function ignoreWhitespace() { + $this->position += strspn($this->rawtext, " \n\r\t", $this->position); + } + + /** + * Begins the parsing operation, setting up the parsed and unparsed + * XML entity decorators if necessary then delegating further work + * to parent + * @param string XML document to parse + * @access protected + * @return void + */ + function parse($data) { + parent::parse($data); + } +} + +/** +* Default NullHandler for methods which were not set by user +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_NullHandler { + /** + * Generic handler method which does nothing + * @access protected + * @return void + */ + function DoNothing() { + } +} + +/** +* User interface class. All user calls should only be made to this class +* @package XML_HTMLSax3 +* @access public +*/ +class XML_HTMLSax3 { + /** + * Instance of concrete subclass of XML_HTMLSax3_StateParser + * @var XML_HTMLSax3_StateParser + * @access private + */ + var $state_parser; + + /** + * Constructs XML_HTMLSax3 selecting concrete StateParser subclass + * depending on PHP version being used as well as setting the default + * NullHandler for all callbacks
    + * Example: + *
    +    * $myHandler = new MyHandler();
    +    * $parser = new XML_HTMLSax3();
    +    * $parser->set_object($myHandler);
    +    * $parser->set_option('XML_OPTION_CASE_FOLDING');
    +    * $parser->set_element_handler('myOpenHandler','myCloseHandler');
    +    * $parser->set_data_handler('myDataHandler');
    +    * $parser->parser($xml);
    +    * 
    + * @access public + */ + function XML_HTMLSax3() { + if (version_compare(phpversion(), '4.3', 'ge')) { + $this->state_parser =new XML_HTMLSax3_StateParser_Gtet430($this); + } else { + $this->state_parser =new XML_HTMLSax3_StateParser_Lt430($this); + } + $nullhandler =new XML_HTMLSax3_NullHandler(); + $this->set_object($nullhandler); + $this->set_element_handler('DoNothing', 'DoNothing'); + $this->set_data_handler('DoNothing'); + $this->set_pi_handler('DoNothing'); + $this->set_jasp_handler('DoNothing'); + $this->set_escape_handler('DoNothing'); + } + + /** + * Sets the user defined handler object. Returns a PEAR Error + * if supplied argument is not an object. + * @param object handler object containing SAX callback methods + * @access public + * @return mixed + */ + function set_object(&$object) { + if ( is_object($object) ) { + $this->state_parser->handler_default =& $object; + return true; + } else { + require_once('PEAR.php'); + PEAR::raiseError('XML_HTMLSax3::set_object requires '. + 'an object instance'); + } + } + + /** + * Sets a parser option. By default all options are switched off. + * Returns a PEAR Error if option is invalid
    + * Available options: + *
      + *
    • XML_OPTION_TRIM_DATA_NODES: trim whitespace off the beginning + * and end of data passed to the data handler
    • + *
    • XML_OPTION_LINEFEED_BREAK: linefeeds result in additional data + * handler calls
    • + *
    • XML_OPTION_TAB_BREAK: tabs result in additional data handler + * calls
    • + *
    • XML_OPTION_ENTITIES_UNPARSED: XML entities are returned as + * seperate data handler calls in unparsed form
    • + *
    • XML_OPTION_ENTITIES_PARSED: (PHP 4.3.0+ only) XML entities are + * returned as seperate data handler calls and are parsed with + * PHP's html_entity_decode() function
    • + *
    • XML_OPTION_STRIP_ESCAPES: strips out the -- -- comment markers + * or CDATA markup inside an XML escape, if found.
    • + *
    + * To get HTMLSax to behave in the same way as the native PHP SAX parser, + * using it's default state, you need to switch on XML_OPTION_LINEFEED_BREAK, + * XML_OPTION_ENTITIES_PARSED and XML_OPTION_CASE_FOLDING + * @param string name of parser option + * @param int (optional) 1 to switch on, 0 for off + * @access public + * @return boolean + */ + function set_option($name, $value=1) { + if ( array_key_exists($name,$this->state_parser->parser_options) ) { + $this->state_parser->parser_options[$name] = $value; + return true; + } else { + require_once('PEAR.php'); + PEAR::raiseError('XML_HTMLSax3::set_option('.$name.') illegal'); + } + } + + /** + * Sets the data handler method which deals with the contents of XML + * elements.
    + * The handler method must accept two arguments, the first being an + * instance of XML_HTMLSax3 and the second being the contents of an + * XML element e.g. + *
    +    * function myDataHander(& $parser,$data){}
    +    * 
    + * @param string name of method + * @access public + * @return void + * @see set_object + */ + function set_data_handler($data_method) { + $this->state_parser->handler_object_data =& $this->state_parser->handler_default; + $this->state_parser->handler_method_data = $data_method; + } + + /** + * Sets the open and close tag handlers + *
    The open handler method must accept three arguments; the parser, + * the tag name and an array of attributes e.g. + *
    +    * function myOpenHander(& $parser,$tagname,$attrs=array()){}
    +    * 
    + * The close handler method must accept two arguments; the parser and + * the tag name e.g. + *
    +    * function myCloseHander(& $parser,$tagname){}
    +    * 
    + * @param string name of open method + * @param string name of close method + * @access public + * @return void + * @see set_object + */ + function set_element_handler($opening_method, $closing_method) { + $this->state_parser->handler_object_element =& $this->state_parser->handler_default; + $this->state_parser->handler_method_opening = $opening_method; + $this->state_parser->handler_method_closing = $closing_method; + } + + /** + * Sets the processing instruction handler method e.g. for PHP open + * and close tags
    + * The handler method must accept three arguments; the parser, the + * PI target and data inside the PI + *
    +    * function myPIHander(& $parser,$target, $data){}
    +    * 
    + * @param string name of method + * @access public + * @return void + * @see set_object + */ + function set_pi_handler($pi_method) { + $this->state_parser->handler_object_pi =& $this->state_parser->handler_default; + $this->state_parser->handler_method_pi = $pi_method; + } + + /** + * Sets the XML escape handler method e.g. for comments and doctype + * declarations
    + * The handler method must accept two arguments; the parser and the + * contents of the escaped section + *
    +    * function myEscapeHander(& $parser, $data){}
    +    * 
    + * @param string name of method + * @access public + * @return void + * @see set_object + */ + function set_escape_handler($escape_method) { + $this->state_parser->handler_object_escape =& $this->state_parser->handler_default; + $this->state_parser->handler_method_escape = $escape_method; + } + + /** + * Sets the JSP/ASP markup handler
    + * The handler method must accept two arguments; the parser and + * body of the JASP tag + *
    +    * function myJaspHander(& $parser, $data){}
    +    * 
    + * @param string name of method + * @access public + * @return void + * @see set_object + */ + function set_jasp_handler ($jasp_method) { + $this->state_parser->handler_object_jasp =& $this->state_parser->handler_default; + $this->state_parser->handler_method_jasp = $jasp_method; + } + + /** + * Returns the current string position of the "cursor" inside the XML + * document + *
    Intended for use from within a user defined handler called + * via the $parser reference e.g. + *
    +    * function myDataHandler(& $parser,$data) {
    +    *     echo( 'Current position: '.$parser->get_current_position() );
    +    * }
    +    * 
    + * @access public + * @return int + * @see get_length + */ + function get_current_position() { + return $this->state_parser->position; + } + + /** + * Returns the string length of the XML document being parsed + * @access public + * @return int + */ + function get_length() { + return $this->state_parser->length; + } + + /** + * Start parsing some XML + * @param string XML document + * @access public + * @return void + */ + function parse($data) { + $this->state_parser->parse($data); + } +} +?> \ No newline at end of file diff --git a/engine/lib/XML/HTMLSax3/Decorators.php b/engine/lib/XML/HTMLSax3/Decorators.php new file mode 100644 index 0000000..156d709 --- /dev/null +++ b/engine/lib/XML/HTMLSax3/Decorators.php @@ -0,0 +1,363 @@ + Original port from Python | +// | Authors: Harry Fuecks Port to PEAR + more | +// | Authors: Many @ Sitepointforums Advanced PHP Forums | +// +----------------------------------------------------------------------+ +// +// $Id: Decorators.php,v 1.2 2007/10/29 21:41:35 hfuecks Exp $ +// +/** +* Decorators for dealing with parser options +* @package XML_HTMLSax3 +* @version $Id: Decorators.php,v 1.2 2007/10/29 21:41:35 hfuecks Exp $ +* @see XML_HTMLSax3::set_option +*/ +/** +* Trims the contents of element data from whitespace at start and end +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_Trim { + /** + * Original handler object + * @var object + * @access private + */ + var $orig_obj; + /** + * Original handler method + * @var string + * @access private + */ + var $orig_method; + /** + * Constructs XML_HTMLSax3_Trim + * @param object handler object being decorated + * @param string original handler method + * @access protected + */ + function XML_HTMLSax3_Trim(&$orig_obj, $orig_method) { + $this->orig_obj =& $orig_obj; + $this->orig_method = $orig_method; + } + /** + * Trims the data + * @param XML_HTMLSax3 + * @param string element data + * @access protected + */ + function trimData(&$parser, $data) { + $data = trim($data); + if ($data != '') { + $this->orig_obj->{$this->orig_method}($parser, $data); + } + } +} +/** +* Coverts tag names to upper case +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_CaseFolding { + /** + * Original handler object + * @var object + * @access private + */ + var $orig_obj; + /** + * Original open handler method + * @var string + * @access private + */ + var $orig_open_method; + /** + * Original close handler method + * @var string + * @access private + */ + var $orig_close_method; + /** + * Constructs XML_HTMLSax3_CaseFolding + * @param object handler object being decorated + * @param string original open handler method + * @param string original close handler method + * @access protected + */ + function XML_HTMLSax3_CaseFolding(&$orig_obj, $orig_open_method, $orig_close_method) { + $this->orig_obj =& $orig_obj; + $this->orig_open_method = $orig_open_method; + $this->orig_close_method = $orig_close_method; + } + /** + * Folds up open tag callbacks + * @param XML_HTMLSax3 + * @param string tag name + * @param array tag attributes + * @access protected + */ + function foldOpen(&$parser, $tag, $attrs=array(), $empty = FALSE) { + $this->orig_obj->{$this->orig_open_method}($parser, strtoupper($tag), $attrs, $empty); + } + /** + * Folds up close tag callbacks + * @param XML_HTMLSax3 + * @param string tag name + * @access protected + */ + function foldClose(&$parser, $tag, $empty = FALSE) { + $this->orig_obj->{$this->orig_close_method}($parser, strtoupper($tag), $empty); + } +} +/** +* Breaks up data by linefeed characters, resulting in additional +* calls to the data handler +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_Linefeed { + /** + * Original handler object + * @var object + * @access private + */ + var $orig_obj; + /** + * Original handler method + * @var string + * @access private + */ + var $orig_method; + /** + * Constructs XML_HTMLSax3_LineFeed + * @param object handler object being decorated + * @param string original handler method + * @access protected + */ + function XML_HTMLSax3_LineFeed(&$orig_obj, $orig_method) { + $this->orig_obj =& $orig_obj; + $this->orig_method = $orig_method; + } + /** + * Breaks the data up by linefeeds + * @param XML_HTMLSax3 + * @param string element data + * @access protected + */ + function breakData(&$parser, $data) { + $data = explode("\n",$data); + foreach ( $data as $chunk ) { + $this->orig_obj->{$this->orig_method}($parser, $chunk); + } + } +} +/** +* Breaks up data by tab characters, resulting in additional +* calls to the data handler +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_Tab { + /** + * Original handler object + * @var object + * @access private + */ + var $orig_obj; + /** + * Original handler method + * @var string + * @access private + */ + var $orig_method; + /** + * Constructs XML_HTMLSax3_Tab + * @param object handler object being decorated + * @param string original handler method + * @access protected + */ + function XML_HTMLSax3_Tab(&$orig_obj, $orig_method) { + $this->orig_obj =& $orig_obj; + $this->orig_method = $orig_method; + } + /** + * Breaks the data up by linefeeds + * @param XML_HTMLSax3 + * @param string element data + * @access protected + */ + function breakData(&$parser, $data) { + $data = explode("\t",$data); + foreach ( $data as $chunk ) { + $this->orig_obj->{$this->orig_method}($this, $chunk); + } + } +} +/** +* Breaks up data by XML entities and parses them with html_entity_decode(), +* resulting in additional calls to the data handler
    +* Requires PHP 4.3.0+ +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_Entities_Parsed { + /** + * Original handler object + * @var object + * @access private + */ + var $orig_obj; + /** + * Original handler method + * @var string + * @access private + */ + var $orig_method; + /** + * Constructs XML_HTMLSax3_Entities_Parsed + * @param object handler object being decorated + * @param string original handler method + * @access protected + */ + function XML_HTMLSax3_Entities_Parsed(&$orig_obj, $orig_method) { + $this->orig_obj =& $orig_obj; + $this->orig_method = $orig_method; + } + /** + * Breaks the data up by XML entities + * @param XML_HTMLSax3 + * @param string element data + * @access protected + */ + function breakData(&$parser, $data) { + $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + foreach ( $data as $chunk ) { + $chunk = html_entity_decode($chunk,ENT_NOQUOTES); + $this->orig_obj->{$this->orig_method}($this, $chunk); + } + } +} +/** +* Compatibility with older PHP versions +*/ +if (version_compare(phpversion(), '4.3', '<') && !function_exists('html_entity_decode') ) { + function html_entity_decode($str, $style=ENT_NOQUOTES) { + return strtr($str, + array_flip(get_html_translation_table(HTML_ENTITIES,$style))); + } +} +/** +* Breaks up data by XML entities but leaves them unparsed, +* resulting in additional calls to the data handler
    +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_Entities_Unparsed { + /** + * Original handler object + * @var object + * @access private + */ + var $orig_obj; + /** + * Original handler method + * @var string + * @access private + */ + var $orig_method; + /** + * Constructs XML_HTMLSax3_Entities_Unparsed + * @param object handler object being decorated + * @param string original handler method + * @access protected + */ + function XML_HTMLSax3_Entities_Unparsed(&$orig_obj, $orig_method) { + $this->orig_obj =& $orig_obj; + $this->orig_method = $orig_method; + } + /** + * Breaks the data up by XML entities + * @param XML_HTMLSax3 + * @param string element data + * @access protected + */ + function breakData(&$parser, $data) { + $data = preg_split('/(&.+?;)/',$data,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + foreach ( $data as $chunk ) { + $this->orig_obj->{$this->orig_method}($this, $chunk); + } + } +} + +/** +* Strips the HTML comment markers or CDATA sections from an escape. +* If XML_OPTIONS_FULL_ESCAPES is on, this decorator is not used.
    +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_Escape_Stripper { + /** + * Original handler object + * @var object + * @access private + */ + var $orig_obj; + /** + * Original handler method + * @var string + * @access private + */ + var $orig_method; + /** + * Constructs XML_HTMLSax3_Entities_Unparsed + * @param object handler object being decorated + * @param string original handler method + * @access protected + */ + function XML_HTMLSax3_Escape_Stripper(&$orig_obj, $orig_method) { + $this->orig_obj =& $orig_obj; + $this->orig_method = $orig_method; + } + /** + * Breaks the data up by XML entities + * @param XML_HTMLSax3 + * @param string element data + * @access protected + */ + function strip(&$parser, $data) { + // Check for HTML comments first + if ( substr($data,0,2) == '--' ) { + $patterns = array( + '/^\-\-/', // Opening comment: -- + '/\-\-$/', // Closing comment: -- + ); + $data = preg_replace($patterns,'',$data); + + // Check for XML CDATA sections (note: don't do both!) + } else if ( substr($data,0,1) == '[' ) { + $patterns = array( + '/^\[.*CDATA.*\[/s', // Opening CDATA + '/\].*\]$/s', // Closing CDATA + ); + $data = preg_replace($patterns,'',$data); + } + + $this->orig_obj->{$this->orig_method}($this, $data); + } +} +?> \ No newline at end of file diff --git a/engine/lib/XML/HTMLSax3/States.php b/engine/lib/XML/HTMLSax3/States.php new file mode 100644 index 0000000..c9ef28e --- /dev/null +++ b/engine/lib/XML/HTMLSax3/States.php @@ -0,0 +1,287 @@ + Original port from Python | +// | Authors: Harry Fuecks Port to PEAR + more | +// | Authors: Many @ Sitepointforums Advanced PHP Forums | +// +----------------------------------------------------------------------+ +// +// $Id: States.php,v 1.3 2007/10/29 21:41:35 hfuecks Exp $ +// +/** +* Parsing states. +* @package XML_HTMLSax3 +* @version $Id: States.php,v 1.3 2007/10/29 21:41:35 hfuecks Exp $ +*/ +/** +* Define parser states +*/ +define('XML_HTMLSAX3_STATE_STOP', 0); +define('XML_HTMLSAX3_STATE_START', 1); +define('XML_HTMLSAX3_STATE_TAG', 2); +define('XML_HTMLSAX3_STATE_OPENING_TAG', 3); +define('XML_HTMLSAX3_STATE_CLOSING_TAG', 4); +define('XML_HTMLSAX3_STATE_ESCAPE', 6); +define('XML_HTMLSAX3_STATE_JASP', 7); +define('XML_HTMLSAX3_STATE_PI', 8); +/** +* StartingState searches for the start of any XML tag +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_StartingState { + /** + * @param XML_HTMLSax3_StateParser subclass + * @return constant XML_HTMLSAX3_STATE_TAG + * @access protected + */ + function parse(&$context) { + $data = $context->scanUntilString('<'); + if ($data != '') { + $context->handler_object_data-> + {$context->handler_method_data}($context->htmlsax, $data); + } + $context->IgnoreCharacter(); + return XML_HTMLSAX3_STATE_TAG; + } +} +/** +* Decides which state to move one from after StartingState +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_TagState { + /** + * @param XML_HTMLSax3_StateParser subclass + * @return constant the next state to move into + * @access protected + */ + function parse(&$context) { + switch($context->ScanCharacter()) { + case '/': + return XML_HTMLSAX3_STATE_CLOSING_TAG; + break; + case '?': + return XML_HTMLSAX3_STATE_PI; + break; + case '%': + return XML_HTMLSAX3_STATE_JASP; + break; + case '!': + return XML_HTMLSAX3_STATE_ESCAPE; + break; + default: + $context->unscanCharacter(); + return XML_HTMLSAX3_STATE_OPENING_TAG; + } + } +} +/** +* Dealing with closing XML tags +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_ClosingTagState { + /** + * @param XML_HTMLSax3_StateParser subclass + * @return constant XML_HTMLSAX3_STATE_START + * @access protected + */ + function parse(&$context) { + $tag = $context->scanUntilCharacters('/>'); + if ($tag != '') { + $char = $context->scanCharacter(); + if ($char == '/') { + $char = $context->scanCharacter(); + if ($char != '>') { + $context->unscanCharacter(); + } + } + $context->handler_object_element-> + {$context->handler_method_closing}($context->htmlsax, $tag, FALSE); + } + return XML_HTMLSAX3_STATE_START; + } +} +/** +* Dealing with opening XML tags +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_OpeningTagState { + /** + * Handles attributes + * @param string attribute name + * @param string attribute value + * @return void + * @access protected + * @see XML_HTMLSax3_AttributeStartState + */ + function parseAttributes(&$context) { + $Attributes = array(); + + $context->ignoreWhitespace(); + $attributename = $context->scanUntilCharacters("=/> \n\r\t"); + while ($attributename != '') { + $attributevalue = NULL; + $context->ignoreWhitespace(); + $char = $context->scanCharacter(); + if ($char == '=') { + $context->ignoreWhitespace(); + $char = $context->ScanCharacter(); + if ($char == '"') { + $attributevalue= $context->scanUntilString('"'); + $context->IgnoreCharacter(); + } else if ($char == "'") { + $attributevalue = $context->scanUntilString("'"); + $context->IgnoreCharacter(); + } else { + $context->unscanCharacter(); + $attributevalue = + $context->scanUntilCharacters("> \n\r\t"); + } + } else if ($char !== NULL) { + $attributevalue = NULL; + $context->unscanCharacter(); + } + $Attributes[$attributename] = $attributevalue; + + $context->ignoreWhitespace(); + $attributename = $context->scanUntilCharacters("=/> \n\r\t"); + } + return $Attributes; + } + + /** + * @param XML_HTMLSax3_StateParser subclass + * @return constant XML_HTMLSAX3_STATE_START + * @access protected + */ + function parse(&$context) { + $tag = $context->scanUntilCharacters("/> \n\r\t"); + if ($tag != '') { + $this->attrs = array(); + $Attributes = $this->parseAttributes($context); + $char = $context->scanCharacter(); + if ($char == '/') { + $char = $context->scanCharacter(); + if ($char != '>') { + $context->unscanCharacter(); + } + $context->handler_object_element-> + {$context->handler_method_opening}($context->htmlsax, $tag, + $Attributes, TRUE); + $context->handler_object_element-> + {$context->handler_method_closing}($context->htmlsax, $tag, + TRUE); + } else { + $context->handler_object_element-> + {$context->handler_method_opening}($context->htmlsax, $tag, + $Attributes, FALSE); + } + } + return XML_HTMLSAX3_STATE_START; + } +} + +/** +* Deals with XML escapes handling comments and CDATA correctly +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_EscapeState { + /** + * @param XML_HTMLSax3_StateParser subclass + * @return constant XML_HTMLSAX3_STATE_START + * @access protected + */ + function parse(&$context) { + $char = $context->ScanCharacter(); + if ($char == '-') { + $char = $context->ScanCharacter(); + if ($char == '-') { + $context->unscanCharacter(); + $context->unscanCharacter(); + $text = $context->scanUntilString('-->'); + $text .= $context->scanCharacter(); + $text .= $context->scanCharacter(); + } else { + $context->unscanCharacter(); + $text = $context->scanUntilString('>'); + } + } else if ( $char == '[') { + $context->unscanCharacter(); + $text = $context->scanUntilString(']>'); + $text.= $context->scanCharacter(); + } else { + $context->unscanCharacter(); + $text = $context->scanUntilString('>'); + } + + $context->IgnoreCharacter(); + if ($text != '') { + $context->handler_object_escape-> + {$context->handler_method_escape}($context->htmlsax, $text); + } + return XML_HTMLSAX3_STATE_START; + } +} +/** +* Deals with JASP/ASP markup +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_JaspState { + /** + * @param XML_HTMLSax3_StateParser subclass + * @return constant XML_HTMLSAX3_STATE_START + * @access protected + */ + function parse(&$context) { + $text = $context->scanUntilString('%>'); + if ($text != '') { + $context->handler_object_jasp-> + {$context->handler_method_jasp}($context->htmlsax, $text); + } + $context->IgnoreCharacter(); + $context->IgnoreCharacter(); + return XML_HTMLSAX3_STATE_START; + } +} +/** +* Deals with XML processing instructions +* @package XML_HTMLSax3 +* @access protected +*/ +class XML_HTMLSax3_PiState { + /** + * @param XML_HTMLSax3_StateParser subclass + * @return constant XML_HTMLSAX3_STATE_START + * @access protected + */ + function parse(&$context) { + $target = $context->scanUntilCharacters(" \n\r\t"); + $data = $context->scanUntilString('?>'); + if ($data != '') { + $context->handler_object_pi-> + {$context->handler_method_pi}($context->htmlsax, $target, $data); + } + $context->IgnoreCharacter(); + $context->IgnoreCharacter(); + return XML_HTMLSAX3_STATE_START; + } +} +?> \ No newline at end of file diff --git a/engine/lib/core.function.php b/engine/lib/core.function.php new file mode 100755 index 0000000..607cf4f --- /dev/null +++ b/engine/lib/core.function.php @@ -0,0 +1,140 @@ +$value){ + if (substr($key,0,5)=="HTTP_") { + $key=str_replace(" ","-",ucwords(strtolower(str_replace("_"," ",substr($key,5))))); + $out[$key]=$value; + } + } + return $out; + } +} +function safeUrlString( $str ){ + $str = urldecode($str); + return str_replace( array( '.' , '/' ) , array() , $str ); +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..2c81aac --- /dev/null +++ b/index.php @@ -0,0 +1,29 @@ + diff --git a/js/core.js b/js/core.js new file mode 100755 index 0000000..6a35c8d --- /dev/null +++ b/js/core.js @@ -0,0 +1,750 @@ +var TEMP = {}; +TEMP.MESSAGE = '
    {message}
    '; +//normal function for apps + +function afterAjax(res) { + var error = false; + var showAjaxMessage = function(res) { + res = res.replace(/([\s\S]+?)<\/message>/, function(message) { + if (showMessage && arguments.length > 2) { + if (arguments[1] == 'error') { + error = true; + } + showMessage(arguments[2], arguments[1]); + } + return ''; + }); + return res; + } + if (typeof(res) == 'string' && res) { + res = showAjaxMessage(res); + } else if (typeof(res) == 'object' && typeof(res.message) == 'string' && res.message) { + showAjaxMessage(res.message); + } + if (error) { + return false; + } else { + return res; + } +} + +function showMessage(message) { + var res = {}; + res.message = message; + if (arguments.length >= 2) { + res.type = arguments[1]; + } else { + res.type = 'notice'; + } + res = $(res).substitute(TEMP.MESSAGE); + if ($('#js_message').length > 0 && $('#js_message').get(0).messageAuto) { + clearTimeout($('#js_message').get(0).messageAuto); + } + var messageBox = popBox(res, 'js_message', 999); + $('#js_message').css('z-index', 999); + $('#js_message').get(0).messageAuto = setTimeout(function() { + $('#js_message').hide(); + }, 3000); +} + +function popBox(res, id) { + if (typeof(id) == 'string') { + if (typeof(res) != 'object' && $(res).length == 0) { + res = $('
    ' + res + '
    '); + } else { + res = $(res); + } + if (res.length > 0) { + var box = $('#' + id); + if (box.length < 1) { + box = $('
    '); + box.appendTo("body"); + if (res.find('.close').length > 0) { + $('#' + id).on('click', '.close', function() { + $('#' + id).hide(); + }); + } + } else { + box.html(''); + } + box.show(); + if (arguments.length > 2 && parseInt(arguments[2], 10) > 0) { + res.appendTo(box).pop(arguments[2]); + } else { + res.appendTo(box).pop(); + } + //box.children().not(res).remove(); + autoEvent('#' + id); + return res.parent(); + } + } +} + +function forceInt(obj) { + var oldVal = $(obj).val(); + var newVal = $(obj).val().replace(/[^\d\.]/g, '').replace(/\..*/, '').replace(/^0+/, '0').replace(/^0*([1-9])/, '$1'); + if (newVal != oldVal) $(obj).val(newVal); +} + +function forceFloat(obj) { + var oldVal = $(obj).val(); + var newVal = $(obj).val().replace(/[^\d\.]/g, ''); + newVal = newVal.match(/\d*\.*\d{0,2}/)[0]; + newVal = newVal.replace(/\.+/g, '.').replace(/^\./, '0.').replace(/^0+/, '0').replace(/^0*([1-9])/, '$1'); + if (newVal != oldVal) $(obj).val(newVal); +} + +function selectAll(obj, name) { + if ($(obj).attr('checked') && name) { + $(document).find(':checkbox[name*=' + name + ']').each(function() { + if (!$(this).attr('checked')) { + $(this).attr('checked', 'checked'); + } + }); + return true; + } else if (name) { + $(document).find(':checkbox[name*=' + name + ']').each(function() { + if ($(this).attr('checked')) { + $(this).attr('checked', false); + } + }); + return false; + } +} + +function jConfirm(target, text) { + var type = 'click'; + var $target = $(target); + var saveHandlers = function() { + var events = $.data(target, 'events'); + if (target.href) { + // No handlers but we have href + var url = target.href; + $target.bind('click', function() { + window.location.href = url; + }); + target.href = 'javascript:void(0)'; + events = $.data(target, 'events'); + } else if (!events) { + // There are no handlers to save. + return; + } + target._handlers = new Array(); + for (var i in events[type]) { + target._handlers.push(events[type][i]); + } + } + var handler = function() { + var text = $(this).attr('confirm'); + if (!text) { + text = '确认进行此操作吗?'; + } + var html = '
    ' + '
    ' + '' + '' + '' + '' + '' + '' + '
    ' + '
    ' + '

    ' + '' + text + '

    ' + '

    ' + '' + '??' + '' + '' + '??' + '' + '

    ' + '
    ' + '
    ' + '
    ' + '
    '; + // show confirm box + var $box = $('#confirmBox'); + if ($box.length == 0) { + $box = $('
    '); + $box.appendTo("body"); + } else { + $box.html(''); + $box.html('
    '); + } + $box.show(); + var height = 95; + var width = 200; + var rect = this.getBoundingClientRect(); + var sizeObj = $(this).getObjSize(); + var newLeft = parseInt(rect.left + $(document).scrollLeft(), 10) + parseInt((sizeObj.width - width) / 2, 10); + if (newLeft + width > $(document).width()) { + newLeft = $(document).width() - width; + } + $box.css("top", parseInt(rect.top + $(document).scrollTop(), 10) - height + "px").css("left", newLeft + "px"); + $box.css({ + 'width': width + 'px', + 'height': height + 'px' + }); + $('#confirmBox .confirmMask').css({ + 'width': width + 'px', + 'height': height + 'px' + }); + $('#confirmBox .confirmMask').show(); + $('#confirmBox .confirmBody').html(html); + $('#confirmBox .confirmMask').slideUp('normal'); + $('#confirmBox .confirmBody .yes').click(function() { + if (target._handlers != undefined) { + $.each(target._handlers, function() { + $target.click(this.handler); + }); + } + // Trigger click event. + $target.click(); + $target.unbind(type); + $('#confirmBox .confirmMask').slideDown('normal', function() { + $target.one(type, handler); + $('#confirmBox').hide(); + }); + }); + $('#confirmBox .confirmBody .no').click(function() { + $('#confirmBox .confirmMask').slideDown('normal', function() { + $('#confirmBox').hide(); + $target.one(type, handler); + }); + }); + return false; + }; + saveHandlers(); + $target.unbind(type); + $target.one('click', handler); +} + +function textCount(obj) { + if (!$(obj).attr('textCount')) { + return true; + } else { + var noticeDiv = false; + $(obj).parents('div').each(function() { + if (noticeDiv == false && $(this).find('.textCountTip').length > 0) { + noticeDiv = $(this).find('.textCountTip'); + return false; + } + }); + var count = $.trim($(obj).val()).length; + var limit = parseInt($(obj).attr('textCount'), 10); + if (limit >= count) { + if ($(obj).hasClass('wrongInput')) { + $(obj).removeClass('wrongInput'); + } + noticeDiv.html('您还能输入' + (limit - count) + '个字'); + return true; + } else { + if (!$(obj).hasClass('wrongInput')) { + $(obj).addClass('wrongInput'); + } + noticeDiv.html('已超过' + (count - limit) + '个字'); + return false; + } + } +} + +function ajaxBox(url) { + var data = {}; + if (arguments.length > 1) { + data = arguments[1]; + } + $.post(url, data, function(res) { + if (res) { + popBox(res, 'js_ajaxBox', 500).addMask( document , 0.5, 250 ); + if ($("#js_ajaxBox .Move").length >= 1) { + var size = $("#js_ajaxBox").getObjSize(); + var left = $(document).width() - size.width; + var top = $(document).height() - size.height; + $("#js_ajaxBox").children(':first').Drags({ + handler: '.Move', + area: [0, 0, left, top], + zIndex: 200 + }); + } + return false; + } else { + $('#js_ajaxBox').hide().html(''); + return false; + } + }); +} + +function autoEvent() { + var objs; + if (arguments.length > 0) { + objs = $(arguments[0]).find('[action-type],[confirm],[hoverTip],[urlToAjax],[textCount]'); + } else { + objs = $('[action-type],[confirm],[hoverTip],[urlToAjax],[textCount]'); + } + if (objs.not('[switch]').length > 0) { + objs.not('[switch]').bind('click', function() { + if ($(this).attr('action-type') == 'ajaxBox') { + if ($(this).attr('action-data')) { + ajaxBox($(this).attr('action-data')); + } + } else if ($(this).attr('action-type') == 'fun') { + if ($(this).attr('action-data')) { + var fn = window[$(this).attr('action-data')]; + if (typeof(fn) == 'function') { + fn(this); + } + } + } else if ($(this).attr('action-type') == 'selectAll') { + if ($(this).attr('action-data')) { + var name = $(this).attr('action-data'); + if (select_all(this, name)) { + $('[action-type=selectAll]').filter('[action-data=' + name + ']').attr('checked', true); + } else { + $('[action-type=selectAll]').filter('[action-data=' + name + ']').attr('checked', false); + } + } + } + }); + //check if has selectAll + var names = {}; + objs.filter('[action-type=selectAll]').each(function() { + var obj = this; + var name = $(this).attr('action-data'); + if (name && names[name] != true) { + $(':checkbox[name*=' + name + ']').live('click', function() { + if ($(':checkbox[name*=' + name + ']:checked').length != $(':checkbox[name*=' + name + ']').length) { + $('[action-type=selectAll]').filter('[action-data=' + name + ']').attr('checked', false); + } else { + $('[action-type=selectAll]').filter('[action-data=' + name + ']').attr('checked', true); + } + }); + names[name] = true; + } + }); + //check if has confirm + objs.filter('[confirm]').each(function() { + if (typeof($(this).attr('confirm')) != 'undefined') { + jConfirm(this, $(this).attr('confirm')); + } + }); + } + objs.filter('[hoverTip]').hover( + + function() { + $($(this).attr('hoverTip')).show(); + }, function() { + $($(this).attr('hoverTip')).hide(); + }); + objs.filter('[urlToAjax]').each(function() { + var fn = window[$(this).attr('urlToAjax')]; + if (typeof(fn) == 'function') { + $(this).find('a').each(function() { + var url = $(this).attr('href'); + if (url && url != '#' && url.substr(0, 11).toLowerCase() != 'javascript:') { + $(this).attr('href', 'javascript:void(0)'); + $(this).bind('click', function() { + fn(this, url); + }); + } + }); + } + }); + objs.filter('[textCount]').each(function() { + textCount(this); + $(this).bind('propertychange', function(e) { + e.preventDefault(); + textCount(this); + }).bind("input", function() { + textCount(this); + }); + }); +} +//(function($) { +$.extend($.fn, { + getCss: function(key) { + var v = parseInt(this.css(key)); + if (isNaN(v)) return false; + return v; + } +}); +$.fn.Drags = function(opts) { + var ps = $.extend({ + zIndex: 20, + opacity: .7, + handler: null, + area: null, + onMove: function() {}, + onDrop: function() {} + }, opts); + var dragndrop = { + drag: function(e) { + var dragData = e.data.dragData; + var left = dragData.left + e.pageX - dragData.offLeft; + var top = dragData.top + e.pageY - dragData.offTop; + if (dragData.area) { + left = Math.min(Math.max(dragData.area[0], left), dragData.area[2]); + top = Math.min(Math.max(dragData.area[1], top), dragData.area[3]); + } + //left = Math.min( Math.max( 0 , left ) , ps.maxLeft ); + //top = Math.min( Math.max( 0 , top ) , ps.maxTop ); + dragData.target.css({ + left: left, + top: top + }); + dragData.handler.css({ + cursor: 'move' + }); + dragData.onMove(e); + e = e || window.event; + if (e.stopProgation) { + e.stopPropagation(); + } else { + e.cancelBubble = true; + } + if (e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; + } + }, + drop: function(e) { + var dragData = e.data.dragData; + dragData.target.css(dragData.oldCss); //.css({ 'opacity': '' }); + //dragData.handler.css('cursor', dragData.oldCss.cursor); + dragData.onDrop(e); + $(document).unbind('mousemove', dragndrop.drag).unbind('mouseup', dragndrop.drop); + } + } + return this.each(function() { + var me = this; + var handler = null; + if (typeof ps.handler == 'undefined' || ps.handler == null) handler = $(me); + else handler = (typeof ps.handler == 'string' ? $(ps.handler, this) : ps.handle); + handler.bind('mousedown', { + e: me + }, function(s) { + var target = $(s.data.e); + var oldCss = {}; + if (target.css('position') != 'absolute') { + try { + target.position(oldCss); + } catch (ex) {} + target.css('position', 'absolute'); + } + oldCss.cursor = target.css('cursor') || 'default'; + //oldCss.opacity = target.getCss('opacity') || 1; + var dragData = { + left: oldCss.left || target.getCss('left') || 0, + top: oldCss.top || target.getCss('top') || 0, + width: target.width() || target.getCss('width'), + height: target.height() || target.getCss('height'), + offLeft: s.pageX, + offTop: s.pageY, + oldCss: oldCss, + area: ps.area, + onMove: ps.onMove, + onDrop: ps.onDrop, + handler: handler, + target: target + } + //target.css('opacity', ps.opacity); + $(document).bind('mousemove', { + dragData: dragData + }, dragndrop.drag).bind('mouseup', { + dragData: dragData + }, dragndrop.drop); + }); + }); +} +//})(jQuery); +$(function() { + autoEvent(); +}); +//add on +(function($, afterAjax) { + var inIframe = true; + var ajaxLock = {}; + var lastTargetInfo = false; + var getEvent = function() { + if (document.all) return window.event; + func = getEvent.caller; + while (func != null && func.arguments) { + var arg0 = func.arguments[0]; + if (arg0) { + if ((arg0.constructor == Event || arg0.constructor == MouseEvent) || (typeof(arg0) == "object" && arg0.preventDefault && arg0.stopPropagation)) { + return arg0; + } + } + func = func.caller; + } + return null; + } + var getlastObj = function() { + var event = getEvent(); + if (event) { + var elem = event.srcElement || event.target; + if (elem && typeof(elem.nodeType) != undefined && elem.nodeType) { + return elem; + } else { + return false; + } + } else { + return false; + } + } + var originalAjax = $.ajax; + $.ajax = function() { + if (arguments.length > 0) { + var url = arguments[0].url; + if (ajaxLock[url] == true) { + return; + } + var originalSuccess = function() {}; + var cleanLock = function() { + ajaxLock[url] = false; + }; + if (arguments[0].success) { + originalSuccess = arguments[0].success; + } + if (inIframe) { + var elem = getlastObj(); + if (elem && elem != document) { + lastTargetInfo = {}; + lastTargetInfo.isLastTarget = true; + lastTargetInfo.rect = elem.getBoundingClientRect(); + lastTargetInfo.size = $(elem).getObjSize(); + } + } + arguments[0].success = function(res) { + cleanLock(); + if (afterAjax && typeof(afterAjax) == 'function') { + res = afterAjax(res, lastTargetInfo); + } + if (res !== false) originalSuccess(res, lastTargetInfo); + } + ajaxLock[url] = true; + return originalAjax.apply(this, arguments); + } + }; + $.fn.getObjSize = function() { + var size = { + 'width': 0, + 'height': 0, + 'top': 0, + 'left': 0 + }; + var level = 5; + var obj = this; + while (obj.outerHeight() == 0 && obj.length > 0 && level > 0) { + if (arguments.length == 1) { + obj = obj.children().find(arguments[0]); + } else { + obj = obj.children(':first'); + } + level = level - 1; + } + size.width = obj.outerWidth(); + size.height = obj.outerHeight(); + return size; + }; + $.fn.getObjSize = function() { + var size = { + 'width': 0, + 'height': 0, + 'top': 0, + 'left': 0 + }; + var level = 5; + var obj = this; + while (obj.outerHeight() == 0 && obj.length > 0 && level > 0) { + if (arguments.length == 1) { + obj = obj.children().find(arguments[0]); + } else { + obj = obj.children(':first'); + } + level = level - 1; + } + size.width = obj.outerWidth(); + size.height = obj.outerHeight(); + return size; + }; + $.fn.pop = function() { + var size = this.getObjSize(); + if (this.css('position') != 'absolute') { + this.css('position','absolute'); + } + if (($(window).height() - size.height) / 2 + $(window).scrollTop() < 0) { + this.css("top", "0px"); + } else { + if (inIframe) { + var rect, rectSize; + var elem = getlastObj(); + if (elem == false) { + var func = arguments.callee.caller; + do { + if (func.arguments && func.arguments.length == 2 && func.arguments[1].isLastTarget != undefined) { + var lastTarget = func.arguments[1]; + rect = lastTarget.rect; + rectSize = lastTarget.size; + break; + } + func = func.caller; + } while (func); + if (!func && lastTargetInfo) { + rect = lastTargetInfo.rect; + rectSize = lastTargetInfo.size; + } + } else { + rect = elem.getBoundingClientRect(); + rectSize = $(elem).getObjSize(); + } + if (!rect || !rectSize) { + this.css("top", "50px"); + } else if (!$(elem).is($(this))) { + var mY = parseInt(rect.top, 10) + rectSize.height / 2 + $(document).scrollTop() - size.height / 2; + if (mY + size.height > $(window).height() + $(window).scrollTop()) { + mY = $(window).scrollTop() + $(window).height() - size.height; + } + if (mY < 0) { + mY = 0; + } + this.css("top", mY + "px"); + } + } else { + this.css("top", ($(window).height() - size.height) / 2 + $(window).scrollTop() + "px"); + } + } + this.css("left", ($(window).width() - size.width) / 2 + $(window).scrollLeft() + "px"); + if (arguments.length > 0 && parseInt(arguments[0], 10) > 0) { + this.css('z-index', parseInt(arguments[0], 10)); + } + if ($(this).find('.js_maskIframe').length == 0 && $.browser.msie && ($.browser.version == "6.0") && !$.support.style) { + if ($(document).find('select').length > 0) { + $(this).wrapInner('
    '); + $('.maskDiv').before(''); + } + } + return this; + }; + $.fn.blink = function() { + var o = {}; + var $target = this; + var id = $(this).attr('id') || $(this).attr('name'); + o[id] = {}; + o[id].begin = 0; + o[id].end = 0; + o[id].lock = false; + o[id].step = 6; + o[id].times = 6; + o[id].color = function(i) { + $target.css('background', 'rgb(255,' + i + ',' + i + ')'); + } + o[id].color_next = function(f) { + if (o[id].begin > o[id].end) { + o[id].begin -= o[id].step; + } else if (o[id].begin < o[id].end) { + o[id].begin += o[id].step; + } else { + o[id].lock = false; + if (typeof(f) == 'function') { + f(); + } + return; + } + o[id].color(o[id].begin); + setTimeout(function() { + o[id].color_next(f); + }, 25); + } + o[id].color_to = function(x, y, f) { + if (o[id].lock) { + return; + } + o[id].begin = x; + o[id].end = y; + o[id].lock = true; + o[id].color_next(f); + } + var _c = 255 - o[id].step * o[id].times; + o[id].color_to(255, _c, function() { + o[id].color_to(_c, 255, function() { + o[id].color_to(255, _c, function() { + o[id].color_to(_c, 255); + }); + }); + }); + return this; + }; + $.fn.substitute = function(str) { + var obj = this[0]; + if (!(Object.prototype.toString.call(str) === '[object String]')) { + return ''; + } + if (!(Object.prototype.toString.call(obj) === '[object Object]' && 'isPrototypeOf' in obj)) { + return str; + } + return str.replace(/\{([^{}]+)\}/g, function(match, key) { + var value = obj[key]; + return (value !== undefined) ? '' + value : ''; + }); + }; + $.fn.setValue = function(json) { + if (typeof(json) == 'string' && arguments.length == 2) { + var key = json; + json = {}; + json[key] = arguments[1]; + } + var _this = this; + var jsonNameFormat = function( json ){ + var prefix = '' , jsonFormated = {}; + if( arguments[1] ){ + prefix = arguments[1]; + } + $.each(json, function(name , value ){ + name = prefix?prefix+'['+name+']':name; + if( typeof(value) == 'object' ){ + //alert(name); + jsonFormated = $.extend( jsonFormated , jsonNameFormat( value , name ) ); + }else{ + jsonFormated[name] = value; + } + }); + return jsonFormated; + }; + if (typeof(json) == 'object') { + json = jsonNameFormat( json ); + $.each(json, function(name, value) { + var obj = $(_this).find(":input[name='" + name + "']"); + if (obj.length > 0) { + switch (obj.get(0).type) { + case 'radio': + case 'checkbox': + obj.filter("[value='" + value + "']").filter(":not(:checked)").click(); + break; + case 'select-one': + case 'textarea': + case 'text': + case 'hidden': + obj.val(value); + break; + } + } + }); + } + return this; + }; + $.fn.addMask = function( obj , opacity, zindex) { + var newCss = {}; + newCss.width = $(obj).width() + 'px'; + newCss.height = $(obj).height() + 'px'; + newCss.position = 'absolute'; + newCss['-moz-opacity'] = opacity; + newCss.opacity = opacity; + newCss['z-index'] = zindex; + newCss.filter = 'alpha(Opacity=' + parseFloat(opacity, 10) * 100 + ')'; + if (arguments.length > 3) { + if (arguments[3]) { + newCss.background = arguments[3]; + } + } else { + newCss.background = '#777'; + } + if( obj == document ){ + newCss.top = '0px'; + newCss.left = '0px'; + }else{ + var rect = $(obj).get(0).getBoundingClientRect(); + newCss.top = rect.top + 'px'; + newCss.left = rect.left + 'px'; + } + var className; + if (arguments.length > 3) { + className = arguments[3]; + } else { + className = 'js-mask'; + } + var maskDiv = $('
    '); + maskDiv.addClass(className); + maskDiv.css(newCss); + maskDiv.appendTo(this); + return this; + }; +})(jQuery, afterAjax); \ No newline at end of file diff --git a/lib/BaseController.class.php b/lib/BaseController.class.php new file mode 100755 index 0000000..74e4a19 --- /dev/null +++ b/lib/BaseController.class.php @@ -0,0 +1,83 @@ + $value) { + $_SESSION[$key] = $value; + } + $_SESSION['__SINA']['TOKEN'] = $tokenInfo['oauth_token']; + $_SESSION['expiresTime'] = $tokenInfo['expires'] + time(); + } + }else{ + Weibo::init( c('akey') , c('skey') ,$_SESSION['__SINA']['TOKEN'] ); + Weibo::setIp('202.110.0.5'); + } + //init weibo Class + } + protected function _add( $key , $value = NULL ){ + if( $value == NULL && is_array($key) ){ + $this->tplParams += $key; + }else{ + $this->tplParams[$key] = $value; + } + } + protected function showMessage( $message , $type = 'notice' , $show = true ){ + $message = ''.$message.''; + if( $show ){ + echo $message; + }else{ + return $message; + } + } + protected function render( $tplName = NULL , $data = array() ){ + if( $data && is_array( $data ) ){ + $data = array_merge( $data , $this->tplParams ); + }else{ + $data = $this->tplParams; + } + if( !$tplName ){ + $tpl = $tplName?$tplName:get_class($this); + if( Url::getMethod() != c('default_method') ){ + $tpl .= '_'.Url::getMethod(); + } + }else{ + $tpl = $tplName; + } + + render( $data , $tpl , $this->layout , $this->layoutTpl ); + } + protected function getAjax( $method , $extra = array() ){ + if( !method_exists( $this , $method ) ) die('Ajax method is not exists' ); + //save info + $url = Url::getUrl(); + + $extra['method'] = $method; + $GLOBALS['__isAjax'] = true; + + Url::setUrl( Url::make($extra) ); + + ob_start(); + $this->$method(); + $html = ob_get_clean(); + //replace back + unset($GLOBALS['__isAjax']); + Url::setUrl( $url ); + + return $html; + } +} \ No newline at end of file diff --git a/lib/app.function.php b/lib/app.function.php new file mode 100755 index 0000000..9d3d377 --- /dev/null +++ b/lib/app.function.php @@ -0,0 +1,99 @@ + 1 ){ + $pre = '
  • 上一页
  • '; + } + if( $page < $page_all ){ + $next = ''; + } + if( $page_all <= 11 ){ + /* 小于等于 11 页 */ + $left_num = $page - 1; + $right_num = $page_all - $page; + }else{ + if( $page > 6 ){ + $left_more = true; + if( $page < $page_all - 5 ){ + $right_more = true; + $left_num = 4; + $right_num = 4; + }else{ + $right_more = false; + $right_num = $page_all - $page; + $left_num = 9 - $right_num; + } + }else{ + $left_num = $page - 1; + $left_more = false; + $right_num = 9 - $left_num; + $right_more = true; + } + } + if( $left_more ){ + $middle .= '
  • 1
  • '; + $middle .= '
  • ...
  • '; + } + for($j=$left_num;$j>0;$j--){ + $i = $page - $j; + if( $i <= 0 ){ + continue; + } + $middle .= '
  • ' . $i .'
  • '; + } + $middle .= '
  • ' . $page . '
  • '; + for($j=1;$j<=$right_num;$j++){ + $i = $page + $j; + if( $i > $page_all ){ + continue; + } + $middle .= '
  • ' . $i .'
  • '; + } + if( $right_more ){ + $middle .= '
  • ...
  • '; + $middle .= '
  • ' . $page_all .'
  • '; + } + return $pre.$middle.$next; +} \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..8178c76 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +readme diff --git a/themes/default/layout.tpl.html b/themes/default/layout.tpl.html new file mode 100755 index 0000000..e37c145 --- /dev/null +++ b/themes/default/layout.tpl.html @@ -0,0 +1,21 @@ + + + + +Engine Title 请修改在 themes/default/layout.tpl.html 修改 + + + + + + +can't find $__showPage html file"; + +?> + + + \ No newline at end of file diff --git a/themes/default/main.tpl.html b/themes/default/main.tpl.html new file mode 100644 index 0000000..e69de29