From 4c35172b95b62ec7d671dc6f1d8279a93a4c8a16 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sun, 13 Jul 2014 17:41:55 +0800 Subject: [PATCH 01/35] First Commit: Create Framework --- README.md | 0 cli/here | 0 docs/here | 0 htdocs/API/v2/here | 0 htdocs/assets/here | 0 htdocs/lib/here | 0 htdocs/lib_web/here | 0 sql/here | 0 8 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md create mode 100644 cli/here create mode 100644 docs/here create mode 100644 htdocs/API/v2/here create mode 100644 htdocs/assets/here create mode 100644 htdocs/lib/here create mode 100644 htdocs/lib_web/here create mode 100644 sql/here diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/cli/here b/cli/here new file mode 100644 index 0000000..e69de29 diff --git a/docs/here b/docs/here new file mode 100644 index 0000000..e69de29 diff --git a/htdocs/API/v2/here b/htdocs/API/v2/here new file mode 100644 index 0000000..e69de29 diff --git a/htdocs/assets/here b/htdocs/assets/here new file mode 100644 index 0000000..e69de29 diff --git a/htdocs/lib/here b/htdocs/lib/here new file mode 100644 index 0000000..e69de29 diff --git a/htdocs/lib_web/here b/htdocs/lib_web/here new file mode 100644 index 0000000..e69de29 diff --git a/sql/here b/sql/here new file mode 100644 index 0000000..e69de29 From 8f58cb6c8e62f6177f85aae79c31911cb4bcac9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=83=E5=85=92=EF=BD=9E?= Date: Sun, 20 Jul 2014 19:03:20 +0800 Subject: [PATCH 02/35] add classes --- .gitignore | 25 + README.md | 12 + htdocs/lib/Database/Database.php | 47 + htdocs/lib/Database/NOTE.md | 8 + htdocs/lib/Database/PDODB.php | 77 + htdocs/lib/{here => Database/UserDB.php} | 0 htdocs/lib/User/ClassGroup.php | 0 htdocs/lib/User/ClassGroupAdmin.php | 0 htdocs/lib/User/NOTE.md | 11 + htdocs/lib/User/User.php | 8 + htdocs/lib/User/UserAdmin.php | 24 + htdocs/lib/User/UserControl.php | 0 htdocs/lib/User/UserGroup.php | 0 htdocs/lib/User/UserGroupAdmin.php | 0 .../lib/assets/FirePHPCore/FirePHP.class.php | 1784 +++++++++++++++++ htdocs/lib/assets/FirePHPCore/LICENSE | 29 + htdocs/lib/assets/FirePHPCore/fb.php | 276 +++ 17 files changed, 2301 insertions(+) create mode 100644 .gitignore create mode 100644 htdocs/lib/Database/Database.php create mode 100644 htdocs/lib/Database/NOTE.md create mode 100644 htdocs/lib/Database/PDODB.php rename htdocs/lib/{here => Database/UserDB.php} (100%) create mode 100644 htdocs/lib/User/ClassGroup.php create mode 100644 htdocs/lib/User/ClassGroupAdmin.php create mode 100644 htdocs/lib/User/NOTE.md create mode 100644 htdocs/lib/User/User.php create mode 100644 htdocs/lib/User/UserAdmin.php create mode 100644 htdocs/lib/User/UserControl.php create mode 100644 htdocs/lib/User/UserGroup.php create mode 100644 htdocs/lib/User/UserGroupAdmin.php create mode 100644 htdocs/lib/assets/FirePHPCore/FirePHP.class.php create mode 100644 htdocs/lib/assets/FirePHPCore/LICENSE create mode 100644 htdocs/lib/assets/FirePHPCore/fb.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a37b901 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# 設定檔 + +# 建立測試用的檔案 +test.php + +# KDE Dolphin自己產生的垃圾 +*.directory +.*.kate-swp +.DS_Store +.*.swp + + +# GitEye產生的 +.project + +# phpdoc產生的垃圾檔案 +docs/phpdoc-cache-* + +# PHP Composer +composer.phar +vendor/ + +# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +# composer.lock diff --git a/README.md b/README.md index e69de29..5d84dcc 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,12 @@ +後端伺服器 +=== +主要的東西都放在Server那邊,處理手機客戶端與伺服器資料的溝通。 + +包含每位學生的學習資料、場地狀況、學習教材。以及處理學習路徑規劃。 + +## 系統需求 + +* PHP5.3 以上,需要有以下Extension: + * pdo_mysql + * zip +* MariaDB 5.5.31 (可用MySQL) diff --git a/htdocs/lib/Database/Database.php b/htdocs/lib/Database/Database.php new file mode 100644 index 0000000..0758ca8 --- /dev/null +++ b/htdocs/lib/Database/Database.php @@ -0,0 +1,47 @@ + + * @link https://github.com/CHU-TDAP/ + * @since 3.0 + */ +class Database { + + /** + * 測試資料庫有無連接成功 + * + * @todo + */ + public function connectTest() { + + } + + /** + * 建立資料庫 + * + * 在資料庫系統內建立一個資料庫。 + * (注意!需有建立資料庫的權限) + * + * @todo + */ + public function createDB() { + + } + + /** + * 建立所有所需的資料表 + * + * @TODO rdkoprk + */ + public function createAllTable() { + + } +} \ No newline at end of file diff --git a/htdocs/lib/Database/NOTE.md b/htdocs/lib/Database/NOTE.md new file mode 100644 index 0000000..7f17973 --- /dev/null +++ b/htdocs/lib/Database/NOTE.md @@ -0,0 +1,8 @@ +Database +=== + +## 全域變數 +* DB_NAME +* DB_HOST +* DB_USER +* DB_PASS \ No newline at end of file diff --git a/htdocs/lib/Database/PDODB.php b/htdocs/lib/Database/PDODB.php new file mode 100644 index 0000000..e22e317 --- /dev/null +++ b/htdocs/lib/Database/PDODB.php @@ -0,0 +1,77 @@ + + * @link https://github.com/CHU-TDAP/ + * @version Version 2.0 + * @see https://github.com/shuliu/myPDO + */ +class PDODB extends PDO { + /** + * 連結資料庫 + * + * @access public + * @author Yuan Chiu + * @version 2 + */ + public function __construct(){ + parent::__construct("mysql:dbname=".DB_NAME.";host:".DB_HOST."; + charset=utf8", + DB_USER, DB_PASS); + + //配合PHP< 5.3.6 PDO沒有charset用的 + //參考: http://gdfan1114.wordpress.com/2013/06/24/php-5-3-6-%E7%89%88-pdo-%E9%85%8D%E5%90%88%E5%AD%98%E5%8F%96%E8%B3%87%E6%96%99%E5%BA%AB%E6%99%82%E7%9A%84%E4%B8%AD%E6%96%87%E5%95%8F%E9%A1%8C/ + $this->exec("set names utf8"); + + } + + // ======================================================================== + /** + * 取得帶有前綴字元的完整資料表名稱 + * + * @access public + * @param string $inputName 資料表名稱 + * @return string 完整的資料表名稱 + * + * @author Yuan Chiu + * @version 3 + */ + public function table($inputName){ + return DB_PREFIX.$inputName; + } + + // ======================================================================== + /** + * 錯誤訊息的陣列 + * + * 改寫Adodb -> ErrorMsg + * + * @access public + * @return array 錯誤訊息 + * + * @since 2013.8.6 + * @author shuliu + * @see https://github.com/shuliu/myPDO/blob/master/PDO.class.php + */ + public function ErrorMsg(){ + $err = parent ::errorinfo(); + if( $err[0]!='00000' ){ + return array('errorCode'=>$err[0],'number'=>$err[1],'message'=>$err[2]); + }else{ + return null; + } + } + + } diff --git a/htdocs/lib/here b/htdocs/lib/Database/UserDB.php similarity index 100% rename from htdocs/lib/here rename to htdocs/lib/Database/UserDB.php diff --git a/htdocs/lib/User/ClassGroup.php b/htdocs/lib/User/ClassGroup.php new file mode 100644 index 0000000..e69de29 diff --git a/htdocs/lib/User/ClassGroupAdmin.php b/htdocs/lib/User/ClassGroupAdmin.php new file mode 100644 index 0000000..e69de29 diff --git a/htdocs/lib/User/NOTE.md b/htdocs/lib/User/NOTE.md new file mode 100644 index 0000000..8a60ff5 --- /dev/null +++ b/htdocs/lib/User/NOTE.md @@ -0,0 +1,11 @@ +User Package +=== + +## UserControl.php +登入使用者帳號所用的 + +## User.php + + +## UserAdmin.php +管理使用者帳號、管理群組 diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php new file mode 100644 index 0000000..08fa72b --- /dev/null +++ b/htdocs/lib/User/User.php @@ -0,0 +1,8 @@ + + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ + +/** + * @see http://code.google.com/p/firephp/issues/detail?id=112 + */ +if (!defined('E_STRICT')) { + define('E_STRICT', 2048); +} +if (!defined('E_RECOVERABLE_ERROR')) { + define('E_RECOVERABLE_ERROR', 4096); +} +if (!defined('E_DEPRECATED')) { + define('E_DEPRECATED', 8192); +} +if (!defined('E_USER_DEPRECATED')) { + define('E_USER_DEPRECATED', 16384); +} + +/** + * Sends the given data to the FirePHP Firefox Extension. + * The data can be displayed in the Firebug Console or in the + * "Server" request tab. + * + * For more information see: http://www.firephp.org/ + * + * @copyright Copyright (C) 2007-2009 Christoph Dorn + * @author Christoph Dorn + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ +class FirePHP { + + /** + * FirePHP version + * + * @var string + */ + const VERSION = '0.3'; // @pinf replace '0.3' with '%%package.version%%' + + /** + * Firebug LOG level + * + * Logs a message to firebug console. + * + * @var string + */ + const LOG = 'LOG'; + + /** + * Firebug INFO level + * + * Logs a message to firebug console and displays an info icon before the message. + * + * @var string + */ + const INFO = 'INFO'; + + /** + * Firebug WARN level + * + * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. + * + * @var string + */ + const WARN = 'WARN'; + + /** + * Firebug ERROR level + * + * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. + * + * @var string + */ + const ERROR = 'ERROR'; + + /** + * Dumps a variable to firebug's server panel + * + * @var string + */ + const DUMP = 'DUMP'; + + /** + * Displays a stack trace in firebug console + * + * @var string + */ + const TRACE = 'TRACE'; + + /** + * Displays an exception in firebug console + * + * Increments the firebug error count. + * + * @var string + */ + const EXCEPTION = 'EXCEPTION'; + + /** + * Displays an table in firebug console + * + * @var string + */ + const TABLE = 'TABLE'; + + /** + * Starts a group in firebug console + * + * @var string + */ + const GROUP_START = 'GROUP_START'; + + /** + * Ends a group in firebug console + * + * @var string + */ + const GROUP_END = 'GROUP_END'; + + /** + * Singleton instance of FirePHP + * + * @var FirePHP + */ + protected static $instance = null; + + /** + * Flag whether we are logging from within the exception handler + * + * @var boolean + */ + protected $inExceptionHandler = false; + + /** + * Flag whether to throw PHP errors that have been converted to ErrorExceptions + * + * @var boolean + */ + protected $throwErrorExceptions = true; + + /** + * Flag whether to convert PHP assertion errors to Exceptions + * + * @var boolean + */ + protected $convertAssertionErrorsToExceptions = true; + + /** + * Flag whether to throw PHP assertion errors that have been converted to Exceptions + * + * @var boolean + */ + protected $throwAssertionExceptions = false; + + /** + * Wildfire protocol message index + * + * @var int + */ + protected $messageIndex = 1; + + /** + * Options for the library + * + * @var array + */ + protected $options = array('maxDepth' => 10, + 'maxObjectDepth' => 5, + 'maxArrayDepth' => 5, + 'useNativeJsonEncode' => true, + 'includeLineNumbers' => true); + + /** + * Filters used to exclude object members when encoding + * + * @var array + */ + protected $objectFilters = array( + 'firephp' => array('objectStack', 'instance', 'json_objectStack'), + 'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack') + ); + + /** + * A stack of objects used to detect recursion during object encoding + * + * @var object + */ + protected $objectStack = array(); + + /** + * Flag to enable/disable logging + * + * @var boolean + */ + protected $enabled = true; + + /** + * The insight console to log to if applicable + * + * @var object + */ + protected $logToInsightConsole = null; + + /** + * When the object gets serialized only include specific object members. + * + * @return array + */ + public function __sleep() + { + return array('options','objectFilters','enabled'); + } + + /** + * Gets singleton instance of FirePHP + * + * @param boolean $AutoCreate + * @return FirePHP + */ + public static function getInstance($AutoCreate = false) + { + if ($AutoCreate===true && !self::$instance) { + self::init(); + } + return self::$instance; + } + + /** + * Creates FirePHP object and stores it for singleton access + * + * @return FirePHP + */ + public static function init() + { + return self::setInstance(new self()); + } + + /** + * Set the instance of the FirePHP singleton + * + * @param FirePHP $instance The FirePHP object instance + * @return FirePHP + */ + public static function setInstance($instance) + { + return self::$instance = $instance; + } + + /** + * Set an Insight console to direct all logging calls to + * + * @param object $console The console object to log to + * @return void + */ + public function setLogToInsightConsole($console) + { + if(is_string($console)) { + if(get_class($this)!='FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) { + throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!'); + } + $this->logToInsightConsole = $this->to('request')->console($console); + } else { + $this->logToInsightConsole = $console; + } + } + + /** + * Enable and disable logging to Firebug + * + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public function setEnabled($Enabled) + { + $this->enabled = $Enabled; + } + + /** + * Check if logging is enabled + * + * @return boolean TRUE if enabled + */ + public function getEnabled() + { + return $this->enabled; + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @param string $Class The class name of the object + * @param array $Filter An array of members to exclude + * @return void + */ + public function setObjectFilter($Class, $Filter) + { + $this->objectFilters[strtolower($Class)] = $Filter; + } + + /** + * Set some options for the library + * + * Options: + * - maxDepth: The maximum depth to traverse (default: 10) + * - maxObjectDepth: The maximum depth to traverse objects (default: 5) + * - maxArrayDepth: The maximum depth to traverse arrays (default: 5) + * - useNativeJsonEncode: If true will use json_encode() (default: true) + * - includeLineNumbers: If true will include line numbers and filenames (default: true) + * + * @param array $Options The options to be set + * @return void + */ + public function setOptions($Options) + { + $this->options = array_merge($this->options,$Options); + } + + /** + * Get options from the library + * + * @return array The currently set options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Set an option for the library + * + * @param string $Name + * @param mixed $Value + * @throws Exception + * @return void + */ + public function setOption($Name, $Value) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + $this->options[$Name] = $Value; + } + + /** + * Get an option from the library + * + * @param string $Name + * @throws Exception + * @return mixed + */ + public function getOption($Name) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + return $this->options[$Name]; + } + + /** + * Register FirePHP as your error handler + * + * Will throw exceptions for each php error. + * + * @return mixed Returns a string containing the previously defined error handler (if any) + */ + public function registerErrorHandler($throwErrorExceptions = false) + { + //NOTE: The following errors will not be caught by this error handler: + // E_ERROR, E_PARSE, E_CORE_ERROR, + // E_CORE_WARNING, E_COMPILE_ERROR, + // E_COMPILE_WARNING, E_STRICT + + $this->throwErrorExceptions = $throwErrorExceptions; + + return set_error_handler(array($this,'errorHandler')); + } + + /** + * FirePHP's error handler + * + * Throws exception for each php error that will occur. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * @param array $errcontext + */ + public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) + { + // Don't throw exception if error reporting is switched off + if (error_reporting() == 0) { + return; + } + // Only throw exceptions for errors we are asking for + if (error_reporting() & $errno) { + + $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline); + if ($this->throwErrorExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + } + } + + /** + * Register FirePHP as your exception handler + * + * @return mixed Returns the name of the previously defined exception handler, + * or NULL on error. + * If no previous handler was defined, NULL is also returned. + */ + public function registerExceptionHandler() + { + return set_exception_handler(array($this,'exceptionHandler')); + } + + /** + * FirePHP's exception handler + * + * Logs all exceptions to your firebug console and then stops the script. + * + * @param Exception $Exception + * @throws Exception + */ + function exceptionHandler($Exception) + { + + $this->inExceptionHandler = true; + + header('HTTP/1.1 500 Internal Server Error'); + + try { + $this->fb($Exception); + } catch (Exception $e) { + echo 'We had an exception: ' . $e; + } + $this->inExceptionHandler = false; + } + + /** + * Register FirePHP driver as your assert callback + * + * @param boolean $convertAssertionErrorsToExceptions + * @param boolean $throwAssertionExceptions + * @return mixed Returns the original setting or FALSE on errors + */ + public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false) + { + $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions; + $this->throwAssertionExceptions = $throwAssertionExceptions; + + if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) { + throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!'); + } + + return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler')); + } + + /** + * FirePHP's assertion handler + * + * Logs all assertions to your firebug console and then stops the script. + * + * @param string $file File source of assertion + * @param int $line Line source of assertion + * @param mixed $code Assertion code + */ + public function assertionHandler($file, $line, $code) + { + if ($this->convertAssertionErrorsToExceptions) { + + $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line); + + if ($this->throwAssertionExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + + } else { + $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line)); + } + } + + /** + * Start a group for following messages. + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + * @throws Exception + */ + public function group($Name, $Options = null) + { + + if (!$Name) { + throw $this->newException('You must specify a label for the group!'); + } + + if ($Options) { + if (!is_array($Options)) { + throw $this->newException('Options must be defined as an array!'); + } + if (array_key_exists('Collapsed', $Options)) { + $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false'; + } + } + + return $this->fb(null, $Name, FirePHP::GROUP_START, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public function groupEnd() + { + return $this->fb(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function log($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::LOG, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function info($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::INFO, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function warn($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::WARN, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function error($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::ERROR, $Options); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public function dump($Key, $Variable, $Options = array()) + { + if (!is_string($Key)) { + throw $this->newException('Key passed to dump() is not a string'); + } + if (strlen($Key)>100) { + throw $this->newException('Key passed to dump() is longer than 100 characters'); + } + if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $Key, $m)) { + throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]'); + } + return $this->fb($Variable, $Key, FirePHP::DUMP, $Options); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public function trace($Label) + { + return $this->fb($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public function table($Label, $Table, $Options = array()) + { + return $this->fb($Table, $Label, FirePHP::TABLE, $Options); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::to() + */ + public static function to() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_to")) { + throw new Exception("FirePHP::to() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_to'), $args); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::plugin() + */ + public static function plugin() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_plugin")) { + throw new Exception("FirePHP::plugin() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_plugin'), $args); + } + + /** + * Check if FirePHP is installed on client + * + * @return boolean + */ + public function detectClientExtension() + { + // Check if FirePHP is installed on client via User-Agent header + if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si',$this->getUserAgent(),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } else + // Check if FirePHP is installed on client via X-FirePHP-Version header + if (@preg_match_all('/^([\.\d]*)$/si',$this->getRequestHeader("X-FirePHP-Version"),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } + return false; + } + + /** + * Log varible to Firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object The variable to be logged + * @return true Return TRUE if message was added to headers, FALSE otherwise + * @throws Exception + */ + public function fb($Object) + { + if($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) { + if(!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message + $this->_logUpgradeClientMessage(); + } + } + + static $insightGroupStack = array(); + + if (!$this->getEnabled()) { + return false; + } + + if ($this->headersSent($filename, $linenum)) { + // If we are logging from within the exception handler we cannot throw another exception + if ($this->inExceptionHandler) { + // Simply echo the error out to the page + echo '
FirePHP ERROR: Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.
'; + } else { + throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); + } + } + + $Type = null; + $Label = null; + $Options = array(); + + if (func_num_args()==1) { + } else + if (func_num_args()==2) { + switch(func_get_arg(1)) { + case self::LOG: + case self::INFO: + case self::WARN: + case self::ERROR: + case self::DUMP: + case self::TRACE: + case self::EXCEPTION: + case self::TABLE: + case self::GROUP_START: + case self::GROUP_END: + $Type = func_get_arg(1); + break; + default: + $Label = func_get_arg(1); + break; + } + } else + if (func_num_args()==3) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + } else + if (func_num_args()==4) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + $Options = func_get_arg(3); + } else { + throw $this->newException('Wrong number of arguments to fb() function!'); + } + + if($this->logToInsightConsole!==null && (get_class($this)=='FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) { + $msg = $this->logToInsightConsole; + if ($Object instanceof Exception) { + $Type = self::EXCEPTION; + } + if($Label && $Type!=self::TABLE && $Type!=self::GROUP_START) { + $msg = $msg->label($Label); + } + switch($Type) { + case self::DUMP: + case self::LOG: + return $msg->log($Object); + case self::INFO: + return $msg->info($Object); + case self::WARN: + return $msg->warn($Object); + case self::ERROR: + return $msg->error($Object); + case self::TRACE: + return $msg->trace($Object); + case self::EXCEPTION: + return $this->plugin('engine')->handleException($Object, $msg); + case self::TABLE: + if (isset($Object[0]) && !is_string($Object[0]) && $Label) { + $Object = array($Label, $Object); + } + return $msg->table($Object[0], array_slice($Object[1],1), $Object[1][0]); + case self::GROUP_START: + $insightGroupStack[] = $msg->group(md5($Label))->open(); + return $msg->log($Label); + case self::GROUP_END: + if(count($insightGroupStack)==0) { + throw new Error('Too many groupEnd() as opposed to group() calls!'); + } + $group = array_pop($insightGroupStack); + return $group->close(); + default: + return $msg->log($Object); + } + } + + if (!$this->detectClientExtension()) { + return false; + } + + $meta = array(); + $skipFinalObjectEncode = false; + + if ($Object instanceof Exception) { + + $meta['file'] = $this->_escapeTraceFile($Object->getFile()); + $meta['line'] = $Object->getLine(); + + $trace = $Object->getTrace(); + if ($Object instanceof ErrorException + && isset($trace[0]['function']) + && $trace[0]['function']=='errorHandler' + && isset($trace[0]['class']) + && $trace[0]['class']=='FirePHP') { + + $severity = false; + switch($Object->getSeverity()) { + case E_WARNING: $severity = 'E_WARNING'; break; + case E_NOTICE: $severity = 'E_NOTICE'; break; + case E_USER_ERROR: $severity = 'E_USER_ERROR'; break; + case E_USER_WARNING: $severity = 'E_USER_WARNING'; break; + case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break; + case E_STRICT: $severity = 'E_STRICT'; break; + case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break; + case E_DEPRECATED: $severity = 'E_DEPRECATED'; break; + case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break; + } + + $Object = array('Class'=>get_class($Object), + 'Message'=>$severity.': '.$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'trigger', + 'Trace'=>$this->_escapeTrace(array_splice($trace,2))); + $skipFinalObjectEncode = true; + } else { + $Object = array('Class'=>get_class($Object), + 'Message'=>$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'throw', + 'Trace'=>$this->_escapeTrace($trace)); + $skipFinalObjectEncode = true; + } + $Type = self::EXCEPTION; + + } else + if ($Type==self::TRACE) { + + $trace = debug_backtrace(); + if (!$trace) return false; + for( $i=0 ; $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if ($trace[$i]['function']=='fb' + || $trace[$i]['function']=='trace' + || $trace[$i]['function']=='send') { + + $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'', + 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'', + 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'', + 'Message'=>$trace[$i]['args'][0], + 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'', + 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'', + 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'', + 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1))); + + $skipFinalObjectEncode = true; + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + + } else + if ($Type==self::TABLE) { + + if (isset($Object[0]) && is_string($Object[0])) { + $Object[1] = $this->encodeTable($Object[1]); + } else { + $Object = $this->encodeTable($Object); + } + + $skipFinalObjectEncode = true; + + } else + if ($Type==self::GROUP_START) { + + if (!$Label) { + throw $this->newException('You must specify a label for the group!'); + } + + } else { + if ($Type===null) { + $Type = self::LOG; + } + } + + if ($this->options['includeLineNumbers']) { + if (!isset($meta['file']) || !isset($meta['line'])) { + + $trace = debug_backtrace(); + for( $i=0 ; $trace && $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if (isset($trace[$i]['file']) + && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip FB::fb() */ + } else { + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + } + } else { + unset($meta['file']); + unset($meta['line']); + } + + $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); + $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION); + + $structure_index = 1; + if ($Type==self::DUMP) { + $structure_index = 2; + $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); + } else { + $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); + } + + if ($Type==self::DUMP) { + $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}'; + } else { + $msg_meta = $Options; + $msg_meta['Type'] = $Type; + if ($Label!==null) { + $msg_meta['Label'] = $Label; + } + if (isset($meta['file']) && !isset($msg_meta['File'])) { + $msg_meta['File'] = $meta['file']; + } + if (isset($meta['line']) && !isset($msg_meta['Line'])) { + $msg_meta['Line'] = $meta['line']; + } + $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']'; + } + + $parts = explode("\n",chunk_split($msg, 5000, "\n")); + + for( $i=0 ; $i2) { + // Message needs to be split into multiple parts + $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + (($i==0)?strlen($msg):'') + . '|' . $part . '|' + . (($isetHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + strlen($part) . '|' . $part . '|'); + } + + $this->messageIndex++; + + if ($this->messageIndex > 99999) { + throw $this->newException('Maximum number (99,999) of messages reached!'); + } + } + } + + $this->setHeader('X-Wf-1-Index',$this->messageIndex-1); + + return true; + } + + /** + * Standardizes path for windows systems. + * + * @param string $Path + * @return string + */ + protected function _standardizePath($Path) + { + return preg_replace('/\\\\+/','/',$Path); + } + + /** + * Escape trace path for windows systems + * + * @param array $Trace + * @return array + */ + protected function _escapeTrace($Trace) + { + if (!$Trace) return $Trace; + for( $i=0 ; $i_escapeTraceFile($Trace[$i]['file']); + } + if (isset($Trace[$i]['args'])) { + $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']); + } + } + return $Trace; + } + + /** + * Escape file information of trace for windows systems + * + * @param string $File + * @return string + */ + protected function _escapeTraceFile($File) + { + /* Check if we have a windows filepath */ + if (strpos($File,'\\')) { + /* First strip down to single \ */ + + $file = preg_replace('/\\\\+/','\\',$File); + + return $file; + } + return $File; + } + + /** + * Check if headers have already been sent + * + * @param string $Filename + * @param integer $Linenum + */ + protected function headersSent(&$Filename, &$Linenum) + { + return headers_sent($Filename, $Linenum); + } + + /** + * Send header + * + * @param string $Name + * @param string $Value + */ + protected function setHeader($Name, $Value) + { + return header($Name.': '.$Value); + } + + /** + * Get user agent + * + * @return string|false + */ + protected function getUserAgent() + { + if (!isset($_SERVER['HTTP_USER_AGENT'])) return false; + return $_SERVER['HTTP_USER_AGENT']; + } + + /** + * Get all request headers + * + * @return array + */ + public static function getAllRequestHeaders() { + static $_cached_headers = false; + if($_cached_headers!==false) { + return $_cached_headers; + } + $headers = array(); + if(function_exists('getallheaders')) { + foreach( getallheaders() as $name => $value ) { + $headers[strtolower($name)] = $value; + } + } else { + foreach($_SERVER as $name => $value) { + if(substr($name, 0, 5) == 'HTTP_') { + $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value; + } + } + } + return $_cached_headers = $headers; + } + + /** + * Get a request header + * + * @return string|false + */ + protected function getRequestHeader($Name) + { + $headers = self::getAllRequestHeaders(); + if (isset($headers[strtolower($Name)])) { + return $headers[strtolower($Name)]; + } + return false; + } + + /** + * Returns a new exception + * + * @param string $Message + * @return Exception + */ + protected function newException($Message) + { + return new Exception($Message); + } + + /** + * Encode an object into a JSON string + * + * Uses PHP's jeson_encode() if available + * + * @param object $Object The object to be encoded + * @return string The JSON string + */ + public function jsonEncode($Object, $skipObjectEncode = false) + { + if (!$skipObjectEncode) { + $Object = $this->encodeObject($Object); + } + + if (function_exists('json_encode') + && $this->options['useNativeJsonEncode']!=false) { + + return json_encode($Object); + } else { + return $this->json_encode($Object); + } + } + + /** + * Encodes a table by encoding each row and column with encodeObject() + * + * @param array $Table The table to be encoded + * @return array + */ + protected function encodeTable($Table) + { + + if (!$Table) return $Table; + + $new_table = array(); + foreach($Table as $row) { + + if (is_array($row)) { + $new_row = array(); + + foreach($row as $item) { + $new_row[] = $this->encodeObject($item); + } + + $new_table[] = $new_row; + } + } + + return $new_table; + } + + /** + * Encodes an object including members with + * protected and private visibility + * + * @param Object $Object The object to be encoded + * @param int $Depth The current traversal depth + * @return array All members of the object + */ + protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1, $MaxDepth = 1) + { + if ($MaxDepth > $this->options['maxDepth']) { + return '** Max Depth ('.$this->options['maxDepth'].') **'; + } + + $return = array(); + + if (is_resource($Object)) { + + return '** '.(string)$Object.' **'; + + } else + if (is_object($Object)) { + + if ($ObjectDepth > $this->options['maxObjectDepth']) { + return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **'; + } + + foreach ($this->objectStack as $refVal) { + if ($refVal === $Object) { + return '** Recursion ('.get_class($Object).') **'; + } + } + array_push($this->objectStack, $Object); + + $return['__className'] = $class = get_class($Object); + $class_lower = strtolower($class); + + $reflectionClass = new ReflectionClass($class); + $properties = array(); + foreach( $reflectionClass->getProperties() as $property) { + $properties[$property->getName()] = $property; + } + + $members = (array)$Object; + + foreach( $properties as $plain_name => $property ) { + + $name = $raw_name = $plain_name; + if ($property->isStatic()) { + $name = 'static:'.$name; + } + if ($property->isPublic()) { + $name = 'public:'.$name; + } else + if ($property->isPrivate()) { + $name = 'private:'.$name; + $raw_name = "\0".$class."\0".$raw_name; + } else + if ($property->isProtected()) { + $name = 'protected:'.$name; + $raw_name = "\0".'*'."\0".$raw_name; + } + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + if (array_key_exists($raw_name,$members) + && !$property->isStatic()) { + + $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1, $MaxDepth + 1); + + } else { + if (method_exists($property,'setAccessible')) { + $property->setAccessible(true); + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else + if ($property->isPublic()) { + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Need PHP 5.3 to get value **'; + } + } + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + + // Include all members that are not defined in the class + // but exist in the object + foreach( $members as $raw_name => $value ) { + + $name = $raw_name; + + if ($name{0} == "\0") { + $parts = explode("\0", $name); + $name = $parts[2]; + } + + $plain_name = $name; + + if (!isset($properties[$name])) { + $name = 'undeclared:'.$name; + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + } + + array_pop($this->objectStack); + + } elseif (is_array($Object)) { + + if ($ArrayDepth > $this->options['maxArrayDepth']) { + return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **'; + } + + foreach ($Object as $key => $val) { + + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($key=='GLOBALS' + && is_array($val) + && array_key_exists('GLOBALS',$val)) { + $val['GLOBALS'] = '** Recursion (GLOBALS) **'; + } + + $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1, $MaxDepth + 1); + } + } else { + if (self::is_utf8($Object)) { + return $Object; + } else { + return utf8_encode($Object); + } + } + return $return; + } + + /** + * Returns true if $string is valid UTF-8 and false otherwise. + * + * @param mixed $str String to be tested + * @return boolean + */ + protected static function is_utf8($str) + { + if(function_exists('mb_detect_encoding')) { + return (mb_detect_encoding($str) == 'UTF-8'); + } + $c=0; $b=0; + $bits=0; + $len=strlen($str); + for($i=0; $i<$len; $i++){ + $c=ord($str[$i]); + if ($c > 128){ + if (($c >= 254)) return false; + elseif ($c >= 252) $bits=6; + elseif ($c >= 248) $bits=5; + elseif ($c >= 240) $bits=4; + elseif ($c >= 224) $bits=3; + elseif ($c >= 192) $bits=2; + else return false; + if (($i+$bits) > $len) return false; + while($bits > 1){ + $i++; + $b=ord($str[$i]); + if ($b < 128 || $b > 191) return false; + $bits--; + } + } + } + return true; + } + + /** + * Converts to and from JSON format. + * + * JSON (JavaScript Object Notation) is a lightweight data-interchange + * format. It is easy for humans to read and write. It is easy for machines + * to parse and generate. It is based on a subset of the JavaScript + * Programming Language, Standard ECMA-262 3rd Edition - December 1999. + * This feature can also be found in Python. JSON is a text format that is + * completely language independent but uses conventions that are familiar + * to programmers of the C-family of languages, including C, C++, C#, Java, + * JavaScript, Perl, TCL, and many others. These properties make JSON an + * ideal data-interchange language. + * + * This package provides a simple encoder and decoder for JSON notation. It + * is intended for use with client-side Javascript applications that make + * use of HTTPRequest to perform server communication functions - data can + * be encoded into JSON notation for use in a client-side javascript, or + * decoded from incoming Javascript requests. JSON format is native to + * Javascript, and can be directly eval()'ed with no further parsing + * overhead + * + * All strings should be in ASCII or UTF-8 format! + * + * LICENSE: Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: Redistributions of source code must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @category + * @package Services_JSON + * @author Michal Migurski + * @author Matt Knapp + * @author Brett Stimmerman + * @author Christoph Dorn + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + + + /** + * Keep a list of objects as we descend into the array so we can detect recursion. + */ + private $json_objectStack = array(); + + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + private function json_utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + private function json_encode($var) + { + + if (is_object($var)) { + if (in_array($var,$this->json_objectStack)) { + return '"** Recursion **"'; + } + } + + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($var), + array_values($var)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + $this->json_objectStack[] = $var; + + // treat it like a regular array + $elements = array_map(array($this, 'json_encode'), $var); + + array_pop($this->json_objectStack); + + foreach($elements as $element) { + if ($element instanceof Exception) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = self::encodeObject($var); + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($vars), + array_values($vars)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return null; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + private function json_name_value($name, $value) + { + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($name=='GLOBALS' + && is_array($value) + && array_key_exists('GLOBALS',$value)) { + $value['GLOBALS'] = '** Recursion **'; + } + + $encoded_value = $this->json_encode($value); + + if ($encoded_value instanceof Exception) { + return $encoded_value; + } + + return $this->json_encode(strval($name)) . ':' . $encoded_value; + } + + /** + * @deprecated + */ + public function setProcessorUrl($URL) + { + trigger_error("The FirePHP::setProcessorUrl() method is no longer supported", E_USER_DEPRECATED); + } + + /** + * @deprecated + */ + public function setRendererUrl($URL) + { + trigger_error("The FirePHP::setRendererUrl() method is no longer supported", E_USER_DEPRECATED); + } +} diff --git a/htdocs/lib/assets/FirePHPCore/LICENSE b/htdocs/lib/assets/FirePHPCore/LICENSE new file mode 100644 index 0000000..3e390f9 --- /dev/null +++ b/htdocs/lib/assets/FirePHPCore/LICENSE @@ -0,0 +1,29 @@ +Software License Agreement (New BSD License) + +Copyright (c) 2006-2009, Christoph Dorn +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Christoph Dorn nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/htdocs/lib/assets/FirePHPCore/fb.php b/htdocs/lib/assets/FirePHPCore/fb.php new file mode 100644 index 0000000..9ed9c42 --- /dev/null +++ b/htdocs/lib/assets/FirePHPCore/fb.php @@ -0,0 +1,276 @@ + + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ + +if(!class_exists('FirePHP')) { + require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'FirePHP.class.php'; +} + +/** + * Sends the given data to the FirePHP Firefox Extension. + * The data can be displayed in the Firebug Console or in the + * "Server" request tab. + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object + * @return true + * @throws Exception + */ +function fb() +{ + $instance = FirePHP::getInstance(true); + + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); +} + + +class FB +{ + /** + * Enable and disable logging to Firebug + * + * @see FirePHP->setEnabled() + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public static function setEnabled($Enabled) + { + $instance = FirePHP::getInstance(true); + $instance->setEnabled($Enabled); + } + + /** + * Check if logging is enabled + * + * @see FirePHP->getEnabled() + * @return boolean TRUE if enabled + */ + public static function getEnabled() + { + $instance = FirePHP::getInstance(true); + return $instance->getEnabled(); + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @see FirePHP->setObjectFilter() + * @param string $Class The class name of the object + * @param array $Filter An array or members to exclude + * @return void + */ + public static function setObjectFilter($Class, $Filter) + { + $instance = FirePHP::getInstance(true); + $instance->setObjectFilter($Class, $Filter); + } + + /** + * Set some options for the library + * + * @see FirePHP->setOptions() + * @param array $Options The options to be set + * @return void + */ + public static function setOptions($Options) + { + $instance = FirePHP::getInstance(true); + $instance->setOptions($Options); + } + + /** + * Get options for the library + * + * @see FirePHP->getOptions() + * @return array The options + */ + public static function getOptions() + { + $instance = FirePHP::getInstance(true); + return $instance->getOptions(); + } + + /** + * Log object to firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object + * @return true + * @throws Exception + */ + public static function send() + { + $instance = FirePHP::getInstance(true); + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); + } + + /** + * Start a group for following messages + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + */ + public static function group($Name, $Options=null) + { + $instance = FirePHP::getInstance(true); + return $instance->group($Name, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public static function groupEnd() + { + return self::send(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function log($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::LOG); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function info($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::INFO); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function warn($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::WARN); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function error($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::ERROR); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public static function dump($Key, $Variable) + { + return self::send($Variable, $Key, FirePHP::DUMP); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public static function trace($Label) + { + return self::send($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public static function table($Label, $Table) + { + return self::send($Table, $Label, FirePHP::TABLE); + } + +} From e9fca64d166bdc418e5f5fe06fc847f5a9a41964 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Thu, 24 Jul 2014 14:25:03 -0700 Subject: [PATCH 03/35] Framework: Database --- .gitignore | 5 +- README.md | 8 + htdocs/composer.json | 10 ++ htdocs/config.sample.php | 105 ++++++++++++ htdocs/lib/Config/Exceptions.php | 11 ++ htdocs/lib/Database/DBAdmin.php | 24 +++ htdocs/lib/Database/DBUser.php | 19 +++ htdocs/lib/Database/Database.php | 152 +++++++++++++++++- htdocs/lib/Database/Exceptions.php | 34 ++++ .../lib/Database/{PDODB.php => MySQLDB.php} | 40 ++--- htdocs/lib/Database/UserDB.php | 0 11 files changed, 376 insertions(+), 32 deletions(-) create mode 100644 htdocs/composer.json create mode 100644 htdocs/config.sample.php create mode 100644 htdocs/lib/Config/Exceptions.php create mode 100644 htdocs/lib/Database/DBAdmin.php create mode 100644 htdocs/lib/Database/DBUser.php create mode 100644 htdocs/lib/Database/Exceptions.php rename htdocs/lib/Database/{PDODB.php => MySQLDB.php} (62%) delete mode 100644 htdocs/lib/Database/UserDB.php diff --git a/.gitignore b/.gitignore index a37b901..30576f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ # 設定檔 +htdocs/config.php # 建立測試用的檔案 test.php +htdocs/tests/ # KDE Dolphin自己產生的垃圾 *.directory @@ -13,7 +15,8 @@ test.php # GitEye產生的 .project -# phpdoc產生的垃圾檔案 +# phpdoc產生的檔案 +docs/ docs/phpdoc-cache-* # PHP Composer diff --git a/README.md b/README.md index 5d84dcc..d2c96cb 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,11 @@ * pdo_mysql * zip * MariaDB 5.5.31 (可用MySQL) + + +## 開發文件 +已將整份專案使用[PHPDocumentor](http://www.phpdoc.org/)產生出[開發文件網站](docs/index.html) + +產生指令: + + phpdoc -d ./htdocs/lib -t ./docs/ diff --git a/htdocs/composer.json b/htdocs/composer.json new file mode 100644 index 0000000..0c5c5d1 --- /dev/null +++ b/htdocs/composer.json @@ -0,0 +1,10 @@ +{ + "name": "chu-tdap/uelearning", + "description": "無所不在學習導引系統之研製", + "authors": [ + { + "name": "Yuan Chiu", + "email": "chyuaner@gmail.com" + } + } +} diff --git a/htdocs/config.sample.php b/htdocs/config.sample.php new file mode 100644 index 0000000..a6e33d2 --- /dev/null +++ b/htdocs/config.sample.php @@ -0,0 +1,105 @@ + + *
  • MD5
  • + *
  • SHA1
  • + *
  • CRYPT
  • + * + */ + define('ENCRYPT_MODE', 'SHA1'); + + /** + * 你的地區 + */ + date_default_timezone_set('Asia/Taipei'); //設定時區 + +// 路徑設定 =================================================================== + /** + * 網站根目錄 + */ + define('UELEARNING_ROOT', __DIR__.'/'); + + /** + * 內部函式庫根目錄 + */ + define('UELEARNING_LIB_ROOT', UELEARNING_ROOT.'lib/'); + + /** + * 這份設定檔的路徑 + */ + define('UELEARNING_CONFIG_PATH', __FILE__); + diff --git a/htdocs/lib/Config/Exceptions.php b/htdocs/lib/Config/Exceptions.php new file mode 100644 index 0000000..14aa2e0 --- /dev/null +++ b/htdocs/lib/Config/Exceptions.php @@ -0,0 +1,11 @@ + + * @version 3.0 + * @package UElearning + * @subpackage Database + */ +class DBAdmin extends Database { + +} \ No newline at end of file diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php new file mode 100644 index 0000000..9b7e632 --- /dev/null +++ b/htdocs/lib/Database/DBUser.php @@ -0,0 +1,19 @@ + 'mysql', + * 'host' => 'localhost', + * 'port' => '3306', + * 'user' => 'user', + * 'password' => '123456', + * 'dbname' => 'chu-elearning', + * 'prefix' => 'chu_' + * )); * - * @author Yuan Chiu - * @link https://github.com/CHU-TDAP/ - * @since 3.0 + * 一個資料表為一個類別,如果要對某資料表進行操作,請參閱 + * + * @author Yuan Chiu + * @version 3.0 + * @package UElearning + * @subpackage Database */ class Database { + /** + * 資料庫伺服器類型 + * + * 目前支援的: + * * mysql + * + * @type string + */ + private $db_type; + + /** + * 資料庫伺服器位址 + * @type string + */ + private $db_host; + + /** + * 資料庫伺服器連結埠 + * @type string + */ + private $db_port; + + /** + * 資料庫帳號 + * @type string + */ + private $db_user; + + /** + * 資料庫密碼 + * @type string + */ + private $db_passwd; + + /** + * 資料庫名稱 + * @type string + */ + private $db_name; + + /** + * 資料表前綴字元 + * @type string + */ + private $db_prefix; + + // ------------------------------------------------------------------------ + + /** + * 資料庫連結物件 + * @type UElearning\Database\PDODB + */ + private $connDB; + + // ======================================================================== + + /** + * 連接資料庫 + * + * @param array $conf (optional) 資料庫相關參數,格式為: + * array( 'type' => 'mysql', + * 'host' => 'localhost', + * 'port' => '3306', + * 'user' => 'user', + * 'password' => '123456', + * 'dbname' => 'chu-elearning', + * 'prefix' => 'chu_' ) + * 若不填寫將會直接使用設定在`config.php`的常數 + * + * @author Yuan Chiu + * @since 3.0.0 + */ + public function __construct($conf = null) { + + // 將資料庫設定資訊帶入 + if(isset($conf)) { + $this->db_type = $conf['type']; + $this->db_host = $conf['host']; + $this->db_port = $conf['port']; + $this->db_user = $conf['user']; + $this->db_passwd = $conf['password']; + $this->db_name = $conf['dbname']; + $this->db_prefix = $conf['prefix']; + } + else { + $this->db_type = DB_TYPE; + $this->db_host = DB_HOST; + $this->db_port = DB_PORT; + $this->db_user = DB_USER; + $this->db_passwd = DB_PASS; + $this->db_name = DB_NAME; + $this->db_prefix = DB_PREFIX; + } + + // 檢查是否有支援所設定的DBMS + if($this->db_type == 'mysql') { + $this->connDB = new MySQLDB($this->db_name, $this->db_host, $this->db_port, $this->db_user, $this->db_passwd); + } + else { + throw new DatabaseNoSupportException($this->db_type); + } + } + + /** + * 轉為完整的資料表名稱(包含前綴字元) + * + * @param string $tableName 資料表名稱 + * @return string 完整的資料表名稱 + * + * @author Yuan Chiu + * @since 3.0.0 + */ + public function table($tableName) { + return $this->db_prefix.$tableName; + } + /** * 測試資料庫有無連接成功 * - * @todo + * @since 3.0.0 */ public function connectTest() { + // TODO: Fill code in } @@ -30,18 +170,18 @@ class Database { * 在資料庫系統內建立一個資料庫。 * (注意!需有建立資料庫的權限) * - * @todo */ public function createDB() { + // TODO: Fill code in } /** * 建立所有所需的資料表 * - * @TODO rdkoprk */ public function createAllTable() { + // TODO: Fill code in } } \ No newline at end of file diff --git a/htdocs/lib/Database/Exceptions.php b/htdocs/lib/Database/Exceptions.php new file mode 100644 index 0000000..de2b675 --- /dev/null +++ b/htdocs/lib/Database/Exceptions.php @@ -0,0 +1,34 @@ +type = $type; + parent::__construct('No support: '.$this->type); + } + + /** + * 取得輸入的資料庫系統名稱 + * @return string 錯誤訊息內容 + */ + public function getType() { + return $this->type; + } +} + diff --git a/htdocs/lib/Database/PDODB.php b/htdocs/lib/Database/MySQLDB.php similarity index 62% rename from htdocs/lib/Database/PDODB.php rename to htdocs/lib/Database/MySQLDB.php index e22e317..daa8fa7 100644 --- a/htdocs/lib/Database/PDODB.php +++ b/htdocs/lib/Database/MySQLDB.php @@ -10,26 +10,31 @@ use \PDO; /** - * 資料庫連接專用類別 + * 資料庫連接專用類別,採用自PDO * * @extends PDO * @author Yuan Chiu - * @link https://github.com/CHU-TDAP/ - * @version Version 2.0 + * @version 3.0 * @see https://github.com/shuliu/myPDO + * @package UElearning + * @subpackage Database */ -class PDODB extends PDO { +class MySQLDB extends PDO { + /** * 連結資料庫 * - * @access public + * @param string $dbname 資料庫名稱 + * @param string $host 資料庫伺服器位址 + * @param int $port 資料庫伺服器連接埠 + * @param string $user 資料庫伺服器帳號 + * @param string $passwd 資料庫伺服器密碼 * @author Yuan Chiu - * @version 2 + * @since 3.0.0 */ - public function __construct(){ - parent::__construct("mysql:dbname=".DB_NAME.";host:".DB_HOST."; - charset=utf8", - DB_USER, DB_PASS); + public function __construct($dbname, $host, $port, $user, $passwd){ + parent::__construct("mysql:dbname=".$dbname.";host:".$host."port=".$port."; + charset=utf8", DB_USER, DB_PASS); //配合PHP< 5.3.6 PDO沒有charset用的 //參考: http://gdfan1114.wordpress.com/2013/06/24/php-5-3-6-%E7%89%88-pdo-%E9%85%8D%E5%90%88%E5%AD%98%E5%8F%96%E8%B3%87%E6%96%99%E5%BA%AB%E6%99%82%E7%9A%84%E4%B8%AD%E6%96%87%E5%95%8F%E9%A1%8C/ @@ -37,21 +42,6 @@ class PDODB extends PDO { } - // ======================================================================== - /** - * 取得帶有前綴字元的完整資料表名稱 - * - * @access public - * @param string $inputName 資料表名稱 - * @return string 完整的資料表名稱 - * - * @author Yuan Chiu - * @version 3 - */ - public function table($inputName){ - return DB_PREFIX.$inputName; - } - // ======================================================================== /** * 錯誤訊息的陣列 diff --git a/htdocs/lib/Database/UserDB.php b/htdocs/lib/Database/UserDB.php deleted file mode 100644 index e69de29..0000000 From 9dcf00eb11d2a81bb42d90ee7db03ff91dabb757 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Thu, 24 Jul 2014 15:42:04 -0700 Subject: [PATCH 04/35] Framework: Database & UserControl --- docs/here | 0 htdocs/lib/Config/Exceptions.php | 2 +- htdocs/lib/Database/DBAdmin.php | 56 ++++++++++++++++++++++++++++++ htdocs/lib/Database/DBUser.php | 18 ++++++++-- htdocs/lib/Database/Database.php | 37 +++++--------------- htdocs/lib/Database/Exceptions.php | 4 ++- htdocs/lib/User/UserAdmin.php | 24 ------------- htdocs/lib/User/UserControl.php | 50 ++++++++++++++++++++++++++ 8 files changed, 135 insertions(+), 56 deletions(-) delete mode 100644 docs/here delete mode 100644 htdocs/lib/User/UserAdmin.php diff --git a/docs/here b/docs/here deleted file mode 100644 index e69de29..0000000 diff --git a/htdocs/lib/Config/Exceptions.php b/htdocs/lib/Config/Exceptions.php index 14aa2e0..057302e 100644 --- a/htdocs/lib/Config/Exceptions.php +++ b/htdocs/lib/Config/Exceptions.php @@ -1,4 +1,4 @@ - 'mysql', + * 'host' => 'localhost', + * 'port' => '3306', + * 'user' => 'user', + * 'password' => '123456', + * 'dbname' => 'chu-elearning', + * 'prefix' => 'chu_' + * )); + * + * 可參考以下範例: + * + * require_once __DIR__.'/config.php'; + * require_once UELEARNING_LIB_ROOT.'Database/DBAdmin.php'; + * use UElearning\Database; + * + * try { + * $db = new Database\DBAdmin(); + * } catch (Database\Exception\DatabaseNoSupportException $e) { + * echo 'No Support in ', $e->getType(); + * } catch (Exception $e) { + * echo 'Caught other exception: ', $e->getMessage(); + * } * * @author Yuan Chiu * @version 3.0 @@ -21,4 +57,24 @@ */ class DBAdmin extends Database { + /** + * 建立資料庫 + * + * 在資料庫系統內建立一個資料庫。 + * (注意!需有建立資料庫的權限) + * + */ + public function createDB() { + // TODO: Fill code in + + } + + /** + * 建立所有所需的資料表 + * + */ + public function createAllTable() { + // TODO: Fill code in + + } } \ No newline at end of file diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index 9b7e632..9875196 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -5,10 +5,24 @@ * * 此檔案針對使用者資料表的功能。 * - * @filesource + * @package UElearning + * @subpackage Database */ +require_once UELEARNING_LIB_ROOT.'Database/Database.php'; +require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; -class DBUser { +/** + * 使用者帳號資料表 + * + * 對資料庫中的使用者資料表進行操作。 + * + * + * @author Yuan Chiu + * @version 3.0 + * @package UElearning + * @subpackage Database + */ +class DBUser extends Database { /** * 資料表名稱 * @type string diff --git a/htdocs/lib/Database/Database.php b/htdocs/lib/Database/Database.php index 01aa901..da13683 100644 --- a/htdocs/lib/Database/Database.php +++ b/htdocs/lib/Database/Database.php @@ -10,16 +10,17 @@ */ require_once UELEARNING_LIB_ROOT.'Database/MySQLDB.php'; require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; +use UElearning\Database\Exception; /** - * 資料庫整體管理 + * 資料庫操作抽象類別 * - * 所有對於資料庫的操作(包含查詢、新增、修改、刪除),一律使用這個物件來操作。 + * 請根據一個資料表創建一個類別,並繼承此類別。所有對於資料表的操作(包含查詢、新增、修改、刪除),一律使用新創已繼承的類別物件。 * - * 例如: + * 基本的操作方式例如: * * use UElearning\Database; - * $db = new Database(array( + * $db = new Database\[資料表類別](array( * 'type' => 'mysql', * 'host' => 'localhost', * 'port' => '3306', @@ -29,14 +30,14 @@ require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; * 'prefix' => 'chu_' * )); * - * 一個資料表為一個類別,如果要對某資料表進行操作,請參閱 + * 實際範例可參考 `DBAdmin` 類別的說明文件 * * @author Yuan Chiu * @version 3.0 * @package UElearning * @subpackage Database */ -class Database { +abstract class Database { /** * 資料庫伺服器類型 @@ -107,6 +108,7 @@ class Database { * 'prefix' => 'chu_' ) * 若不填寫將會直接使用設定在`config.php`的常數 * + * @throws UElearning\Database\Exception\DatabaseNoSupportException * @author Yuan Chiu * @since 3.0.0 */ @@ -137,7 +139,7 @@ class Database { $this->connDB = new MySQLDB($this->db_name, $this->db_host, $this->db_port, $this->db_user, $this->db_passwd); } else { - throw new DatabaseNoSupportException($this->db_type); + throw new Exception\DatabaseNoSupportException($this->db_type); } } @@ -163,25 +165,4 @@ class Database { // TODO: Fill code in } - - /** - * 建立資料庫 - * - * 在資料庫系統內建立一個資料庫。 - * (注意!需有建立資料庫的權限) - * - */ - public function createDB() { - // TODO: Fill code in - - } - - /** - * 建立所有所需的資料表 - * - */ - public function createAllTable() { - // TODO: Fill code in - - } } \ No newline at end of file diff --git a/htdocs/lib/Database/Exceptions.php b/htdocs/lib/Database/Exceptions.php index de2b675..1b370b0 100644 --- a/htdocs/lib/Database/Exceptions.php +++ b/htdocs/lib/Database/Exceptions.php @@ -1,14 +1,16 @@ - + * @version 3.0 + * @package UElearning + * @subpackage User + */ +class UserControl { + + /** + * 建立使用者 + * @since 3.0.0 + */ + public function create() { + // TODO: Fill code in + } + + /** + * 是否已有相同名稱的帳號名稱 + * + * @param string $userName 帳號名稱 + * @return bool 已有相同的帳號名稱 + * @since 3.0.0 + */ + public function isHave($userName) { + // TODO: Fill code in + } + + /** + * 使用者登入 + * @param string $userId 帳號名稱 + * @param string $password 密碼 + * @return string 登入session token + * @since 3.0.0 + */ + public function login($userId, $password) { + // TODO: Fill code in + // 如果登入錯誤,就丟例外 + } +} \ No newline at end of file From b6abb350728926bb729268d0d68065cf17a8a7b1 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Thu, 24 Jul 2014 15:43:06 -0700 Subject: [PATCH 05/35] Remove FirePHP --- .../lib/assets/FirePHPCore/FirePHP.class.php | 1784 ----------------- htdocs/lib/assets/FirePHPCore/LICENSE | 29 - htdocs/lib/assets/FirePHPCore/fb.php | 276 --- 3 files changed, 2089 deletions(-) delete mode 100644 htdocs/lib/assets/FirePHPCore/FirePHP.class.php delete mode 100644 htdocs/lib/assets/FirePHPCore/LICENSE delete mode 100644 htdocs/lib/assets/FirePHPCore/fb.php diff --git a/htdocs/lib/assets/FirePHPCore/FirePHP.class.php b/htdocs/lib/assets/FirePHPCore/FirePHP.class.php deleted file mode 100644 index 67ef84f..0000000 --- a/htdocs/lib/assets/FirePHPCore/FirePHP.class.php +++ /dev/null @@ -1,1784 +0,0 @@ - - * @license http://www.opensource.org/licenses/bsd-license.php - * @package FirePHPCore - */ - -/** - * @see http://code.google.com/p/firephp/issues/detail?id=112 - */ -if (!defined('E_STRICT')) { - define('E_STRICT', 2048); -} -if (!defined('E_RECOVERABLE_ERROR')) { - define('E_RECOVERABLE_ERROR', 4096); -} -if (!defined('E_DEPRECATED')) { - define('E_DEPRECATED', 8192); -} -if (!defined('E_USER_DEPRECATED')) { - define('E_USER_DEPRECATED', 16384); -} - -/** - * Sends the given data to the FirePHP Firefox Extension. - * The data can be displayed in the Firebug Console or in the - * "Server" request tab. - * - * For more information see: http://www.firephp.org/ - * - * @copyright Copyright (C) 2007-2009 Christoph Dorn - * @author Christoph Dorn - * @license http://www.opensource.org/licenses/bsd-license.php - * @package FirePHPCore - */ -class FirePHP { - - /** - * FirePHP version - * - * @var string - */ - const VERSION = '0.3'; // @pinf replace '0.3' with '%%package.version%%' - - /** - * Firebug LOG level - * - * Logs a message to firebug console. - * - * @var string - */ - const LOG = 'LOG'; - - /** - * Firebug INFO level - * - * Logs a message to firebug console and displays an info icon before the message. - * - * @var string - */ - const INFO = 'INFO'; - - /** - * Firebug WARN level - * - * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. - * - * @var string - */ - const WARN = 'WARN'; - - /** - * Firebug ERROR level - * - * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. - * - * @var string - */ - const ERROR = 'ERROR'; - - /** - * Dumps a variable to firebug's server panel - * - * @var string - */ - const DUMP = 'DUMP'; - - /** - * Displays a stack trace in firebug console - * - * @var string - */ - const TRACE = 'TRACE'; - - /** - * Displays an exception in firebug console - * - * Increments the firebug error count. - * - * @var string - */ - const EXCEPTION = 'EXCEPTION'; - - /** - * Displays an table in firebug console - * - * @var string - */ - const TABLE = 'TABLE'; - - /** - * Starts a group in firebug console - * - * @var string - */ - const GROUP_START = 'GROUP_START'; - - /** - * Ends a group in firebug console - * - * @var string - */ - const GROUP_END = 'GROUP_END'; - - /** - * Singleton instance of FirePHP - * - * @var FirePHP - */ - protected static $instance = null; - - /** - * Flag whether we are logging from within the exception handler - * - * @var boolean - */ - protected $inExceptionHandler = false; - - /** - * Flag whether to throw PHP errors that have been converted to ErrorExceptions - * - * @var boolean - */ - protected $throwErrorExceptions = true; - - /** - * Flag whether to convert PHP assertion errors to Exceptions - * - * @var boolean - */ - protected $convertAssertionErrorsToExceptions = true; - - /** - * Flag whether to throw PHP assertion errors that have been converted to Exceptions - * - * @var boolean - */ - protected $throwAssertionExceptions = false; - - /** - * Wildfire protocol message index - * - * @var int - */ - protected $messageIndex = 1; - - /** - * Options for the library - * - * @var array - */ - protected $options = array('maxDepth' => 10, - 'maxObjectDepth' => 5, - 'maxArrayDepth' => 5, - 'useNativeJsonEncode' => true, - 'includeLineNumbers' => true); - - /** - * Filters used to exclude object members when encoding - * - * @var array - */ - protected $objectFilters = array( - 'firephp' => array('objectStack', 'instance', 'json_objectStack'), - 'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack') - ); - - /** - * A stack of objects used to detect recursion during object encoding - * - * @var object - */ - protected $objectStack = array(); - - /** - * Flag to enable/disable logging - * - * @var boolean - */ - protected $enabled = true; - - /** - * The insight console to log to if applicable - * - * @var object - */ - protected $logToInsightConsole = null; - - /** - * When the object gets serialized only include specific object members. - * - * @return array - */ - public function __sleep() - { - return array('options','objectFilters','enabled'); - } - - /** - * Gets singleton instance of FirePHP - * - * @param boolean $AutoCreate - * @return FirePHP - */ - public static function getInstance($AutoCreate = false) - { - if ($AutoCreate===true && !self::$instance) { - self::init(); - } - return self::$instance; - } - - /** - * Creates FirePHP object and stores it for singleton access - * - * @return FirePHP - */ - public static function init() - { - return self::setInstance(new self()); - } - - /** - * Set the instance of the FirePHP singleton - * - * @param FirePHP $instance The FirePHP object instance - * @return FirePHP - */ - public static function setInstance($instance) - { - return self::$instance = $instance; - } - - /** - * Set an Insight console to direct all logging calls to - * - * @param object $console The console object to log to - * @return void - */ - public function setLogToInsightConsole($console) - { - if(is_string($console)) { - if(get_class($this)!='FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) { - throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!'); - } - $this->logToInsightConsole = $this->to('request')->console($console); - } else { - $this->logToInsightConsole = $console; - } - } - - /** - * Enable and disable logging to Firebug - * - * @param boolean $Enabled TRUE to enable, FALSE to disable - * @return void - */ - public function setEnabled($Enabled) - { - $this->enabled = $Enabled; - } - - /** - * Check if logging is enabled - * - * @return boolean TRUE if enabled - */ - public function getEnabled() - { - return $this->enabled; - } - - /** - * Specify a filter to be used when encoding an object - * - * Filters are used to exclude object members. - * - * @param string $Class The class name of the object - * @param array $Filter An array of members to exclude - * @return void - */ - public function setObjectFilter($Class, $Filter) - { - $this->objectFilters[strtolower($Class)] = $Filter; - } - - /** - * Set some options for the library - * - * Options: - * - maxDepth: The maximum depth to traverse (default: 10) - * - maxObjectDepth: The maximum depth to traverse objects (default: 5) - * - maxArrayDepth: The maximum depth to traverse arrays (default: 5) - * - useNativeJsonEncode: If true will use json_encode() (default: true) - * - includeLineNumbers: If true will include line numbers and filenames (default: true) - * - * @param array $Options The options to be set - * @return void - */ - public function setOptions($Options) - { - $this->options = array_merge($this->options,$Options); - } - - /** - * Get options from the library - * - * @return array The currently set options - */ - public function getOptions() - { - return $this->options; - } - - /** - * Set an option for the library - * - * @param string $Name - * @param mixed $Value - * @throws Exception - * @return void - */ - public function setOption($Name, $Value) - { - if (!isset($this->options[$Name])) { - throw $this->newException('Unknown option: ' . $Name); - } - $this->options[$Name] = $Value; - } - - /** - * Get an option from the library - * - * @param string $Name - * @throws Exception - * @return mixed - */ - public function getOption($Name) - { - if (!isset($this->options[$Name])) { - throw $this->newException('Unknown option: ' . $Name); - } - return $this->options[$Name]; - } - - /** - * Register FirePHP as your error handler - * - * Will throw exceptions for each php error. - * - * @return mixed Returns a string containing the previously defined error handler (if any) - */ - public function registerErrorHandler($throwErrorExceptions = false) - { - //NOTE: The following errors will not be caught by this error handler: - // E_ERROR, E_PARSE, E_CORE_ERROR, - // E_CORE_WARNING, E_COMPILE_ERROR, - // E_COMPILE_WARNING, E_STRICT - - $this->throwErrorExceptions = $throwErrorExceptions; - - return set_error_handler(array($this,'errorHandler')); - } - - /** - * FirePHP's error handler - * - * Throws exception for each php error that will occur. - * - * @param int $errno - * @param string $errstr - * @param string $errfile - * @param int $errline - * @param array $errcontext - */ - public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) - { - // Don't throw exception if error reporting is switched off - if (error_reporting() == 0) { - return; - } - // Only throw exceptions for errors we are asking for - if (error_reporting() & $errno) { - - $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline); - if ($this->throwErrorExceptions) { - throw $exception; - } else { - $this->fb($exception); - } - } - } - - /** - * Register FirePHP as your exception handler - * - * @return mixed Returns the name of the previously defined exception handler, - * or NULL on error. - * If no previous handler was defined, NULL is also returned. - */ - public function registerExceptionHandler() - { - return set_exception_handler(array($this,'exceptionHandler')); - } - - /** - * FirePHP's exception handler - * - * Logs all exceptions to your firebug console and then stops the script. - * - * @param Exception $Exception - * @throws Exception - */ - function exceptionHandler($Exception) - { - - $this->inExceptionHandler = true; - - header('HTTP/1.1 500 Internal Server Error'); - - try { - $this->fb($Exception); - } catch (Exception $e) { - echo 'We had an exception: ' . $e; - } - $this->inExceptionHandler = false; - } - - /** - * Register FirePHP driver as your assert callback - * - * @param boolean $convertAssertionErrorsToExceptions - * @param boolean $throwAssertionExceptions - * @return mixed Returns the original setting or FALSE on errors - */ - public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false) - { - $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions; - $this->throwAssertionExceptions = $throwAssertionExceptions; - - if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) { - throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!'); - } - - return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler')); - } - - /** - * FirePHP's assertion handler - * - * Logs all assertions to your firebug console and then stops the script. - * - * @param string $file File source of assertion - * @param int $line Line source of assertion - * @param mixed $code Assertion code - */ - public function assertionHandler($file, $line, $code) - { - if ($this->convertAssertionErrorsToExceptions) { - - $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line); - - if ($this->throwAssertionExceptions) { - throw $exception; - } else { - $this->fb($exception); - } - - } else { - $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line)); - } - } - - /** - * Start a group for following messages. - * - * Options: - * Collapsed: [true|false] - * Color: [#RRGGBB|ColorName] - * - * @param string $Name - * @param array $Options OPTIONAL Instructions on how to log the group - * @return true - * @throws Exception - */ - public function group($Name, $Options = null) - { - - if (!$Name) { - throw $this->newException('You must specify a label for the group!'); - } - - if ($Options) { - if (!is_array($Options)) { - throw $this->newException('Options must be defined as an array!'); - } - if (array_key_exists('Collapsed', $Options)) { - $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false'; - } - } - - return $this->fb(null, $Name, FirePHP::GROUP_START, $Options); - } - - /** - * Ends a group you have started before - * - * @return true - * @throws Exception - */ - public function groupEnd() - { - return $this->fb(null, null, FirePHP::GROUP_END); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::LOG - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function log($Object, $Label = null, $Options = array()) - { - return $this->fb($Object, $Label, FirePHP::LOG, $Options); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::INFO - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function info($Object, $Label = null, $Options = array()) - { - return $this->fb($Object, $Label, FirePHP::INFO, $Options); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::WARN - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function warn($Object, $Label = null, $Options = array()) - { - return $this->fb($Object, $Label, FirePHP::WARN, $Options); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::ERROR - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function error($Object, $Label = null, $Options = array()) - { - return $this->fb($Object, $Label, FirePHP::ERROR, $Options); - } - - /** - * Dumps key and variable to firebug server panel - * - * @see FirePHP::DUMP - * @param string $Key - * @param mixed $Variable - * @return true - * @throws Exception - */ - public function dump($Key, $Variable, $Options = array()) - { - if (!is_string($Key)) { - throw $this->newException('Key passed to dump() is not a string'); - } - if (strlen($Key)>100) { - throw $this->newException('Key passed to dump() is longer than 100 characters'); - } - if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $Key, $m)) { - throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]'); - } - return $this->fb($Variable, $Key, FirePHP::DUMP, $Options); - } - - /** - * Log a trace in the firebug console - * - * @see FirePHP::TRACE - * @param string $Label - * @return true - * @throws Exception - */ - public function trace($Label) - { - return $this->fb($Label, FirePHP::TRACE); - } - - /** - * Log a table in the firebug console - * - * @see FirePHP::TABLE - * @param string $Label - * @param string $Table - * @return true - * @throws Exception - */ - public function table($Label, $Table, $Options = array()) - { - return $this->fb($Table, $Label, FirePHP::TABLE, $Options); - } - - /** - * Insight API wrapper - * - * @see Insight_Helper::to() - */ - public static function to() - { - $instance = self::getInstance(); - if (!method_exists($instance, "_to")) { - throw new Exception("FirePHP::to() implementation not loaded"); - } - $args = func_get_args(); - return call_user_func_array(array($instance, '_to'), $args); - } - - /** - * Insight API wrapper - * - * @see Insight_Helper::plugin() - */ - public static function plugin() - { - $instance = self::getInstance(); - if (!method_exists($instance, "_plugin")) { - throw new Exception("FirePHP::plugin() implementation not loaded"); - } - $args = func_get_args(); - return call_user_func_array(array($instance, '_plugin'), $args); - } - - /** - * Check if FirePHP is installed on client - * - * @return boolean - */ - public function detectClientExtension() - { - // Check if FirePHP is installed on client via User-Agent header - if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si',$this->getUserAgent(),$m) && - version_compare($m[1][0],'0.0.6','>=')) { - return true; - } else - // Check if FirePHP is installed on client via X-FirePHP-Version header - if (@preg_match_all('/^([\.\d]*)$/si',$this->getRequestHeader("X-FirePHP-Version"),$m) && - version_compare($m[1][0],'0.0.6','>=')) { - return true; - } - return false; - } - - /** - * Log varible to Firebug - * - * @see http://www.firephp.org/Wiki/Reference/Fb - * @param mixed $Object The variable to be logged - * @return true Return TRUE if message was added to headers, FALSE otherwise - * @throws Exception - */ - public function fb($Object) - { - if($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) { - if(!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message - $this->_logUpgradeClientMessage(); - } - } - - static $insightGroupStack = array(); - - if (!$this->getEnabled()) { - return false; - } - - if ($this->headersSent($filename, $linenum)) { - // If we are logging from within the exception handler we cannot throw another exception - if ($this->inExceptionHandler) { - // Simply echo the error out to the page - echo '
    FirePHP ERROR: Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.
    '; - } else { - throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); - } - } - - $Type = null; - $Label = null; - $Options = array(); - - if (func_num_args()==1) { - } else - if (func_num_args()==2) { - switch(func_get_arg(1)) { - case self::LOG: - case self::INFO: - case self::WARN: - case self::ERROR: - case self::DUMP: - case self::TRACE: - case self::EXCEPTION: - case self::TABLE: - case self::GROUP_START: - case self::GROUP_END: - $Type = func_get_arg(1); - break; - default: - $Label = func_get_arg(1); - break; - } - } else - if (func_num_args()==3) { - $Type = func_get_arg(2); - $Label = func_get_arg(1); - } else - if (func_num_args()==4) { - $Type = func_get_arg(2); - $Label = func_get_arg(1); - $Options = func_get_arg(3); - } else { - throw $this->newException('Wrong number of arguments to fb() function!'); - } - - if($this->logToInsightConsole!==null && (get_class($this)=='FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) { - $msg = $this->logToInsightConsole; - if ($Object instanceof Exception) { - $Type = self::EXCEPTION; - } - if($Label && $Type!=self::TABLE && $Type!=self::GROUP_START) { - $msg = $msg->label($Label); - } - switch($Type) { - case self::DUMP: - case self::LOG: - return $msg->log($Object); - case self::INFO: - return $msg->info($Object); - case self::WARN: - return $msg->warn($Object); - case self::ERROR: - return $msg->error($Object); - case self::TRACE: - return $msg->trace($Object); - case self::EXCEPTION: - return $this->plugin('engine')->handleException($Object, $msg); - case self::TABLE: - if (isset($Object[0]) && !is_string($Object[0]) && $Label) { - $Object = array($Label, $Object); - } - return $msg->table($Object[0], array_slice($Object[1],1), $Object[1][0]); - case self::GROUP_START: - $insightGroupStack[] = $msg->group(md5($Label))->open(); - return $msg->log($Label); - case self::GROUP_END: - if(count($insightGroupStack)==0) { - throw new Error('Too many groupEnd() as opposed to group() calls!'); - } - $group = array_pop($insightGroupStack); - return $group->close(); - default: - return $msg->log($Object); - } - } - - if (!$this->detectClientExtension()) { - return false; - } - - $meta = array(); - $skipFinalObjectEncode = false; - - if ($Object instanceof Exception) { - - $meta['file'] = $this->_escapeTraceFile($Object->getFile()); - $meta['line'] = $Object->getLine(); - - $trace = $Object->getTrace(); - if ($Object instanceof ErrorException - && isset($trace[0]['function']) - && $trace[0]['function']=='errorHandler' - && isset($trace[0]['class']) - && $trace[0]['class']=='FirePHP') { - - $severity = false; - switch($Object->getSeverity()) { - case E_WARNING: $severity = 'E_WARNING'; break; - case E_NOTICE: $severity = 'E_NOTICE'; break; - case E_USER_ERROR: $severity = 'E_USER_ERROR'; break; - case E_USER_WARNING: $severity = 'E_USER_WARNING'; break; - case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break; - case E_STRICT: $severity = 'E_STRICT'; break; - case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break; - case E_DEPRECATED: $severity = 'E_DEPRECATED'; break; - case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break; - } - - $Object = array('Class'=>get_class($Object), - 'Message'=>$severity.': '.$Object->getMessage(), - 'File'=>$this->_escapeTraceFile($Object->getFile()), - 'Line'=>$Object->getLine(), - 'Type'=>'trigger', - 'Trace'=>$this->_escapeTrace(array_splice($trace,2))); - $skipFinalObjectEncode = true; - } else { - $Object = array('Class'=>get_class($Object), - 'Message'=>$Object->getMessage(), - 'File'=>$this->_escapeTraceFile($Object->getFile()), - 'Line'=>$Object->getLine(), - 'Type'=>'throw', - 'Trace'=>$this->_escapeTrace($trace)); - $skipFinalObjectEncode = true; - } - $Type = self::EXCEPTION; - - } else - if ($Type==self::TRACE) { - - $trace = debug_backtrace(); - if (!$trace) return false; - for( $i=0 ; $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' - || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { - /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ - } else - if (isset($trace[$i]['class']) - && isset($trace[$i+1]['file']) - && $trace[$i]['class']=='FirePHP' - && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { - /* Skip fb() */ - } else - if ($trace[$i]['function']=='fb' - || $trace[$i]['function']=='trace' - || $trace[$i]['function']=='send') { - - $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'', - 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'', - 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'', - 'Message'=>$trace[$i]['args'][0], - 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'', - 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'', - 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'', - 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1))); - - $skipFinalObjectEncode = true; - $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; - $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; - break; - } - } - - } else - if ($Type==self::TABLE) { - - if (isset($Object[0]) && is_string($Object[0])) { - $Object[1] = $this->encodeTable($Object[1]); - } else { - $Object = $this->encodeTable($Object); - } - - $skipFinalObjectEncode = true; - - } else - if ($Type==self::GROUP_START) { - - if (!$Label) { - throw $this->newException('You must specify a label for the group!'); - } - - } else { - if ($Type===null) { - $Type = self::LOG; - } - } - - if ($this->options['includeLineNumbers']) { - if (!isset($meta['file']) || !isset($meta['line'])) { - - $trace = debug_backtrace(); - for( $i=0 ; $trace && $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' - || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { - /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ - } else - if (isset($trace[$i]['class']) - && isset($trace[$i+1]['file']) - && $trace[$i]['class']=='FirePHP' - && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { - /* Skip fb() */ - } else - if (isset($trace[$i]['file']) - && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') { - /* Skip FB::fb() */ - } else { - $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; - $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; - break; - } - } - } - } else { - unset($meta['file']); - unset($meta['line']); - } - - $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); - $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION); - - $structure_index = 1; - if ($Type==self::DUMP) { - $structure_index = 2; - $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); - } else { - $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); - } - - if ($Type==self::DUMP) { - $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}'; - } else { - $msg_meta = $Options; - $msg_meta['Type'] = $Type; - if ($Label!==null) { - $msg_meta['Label'] = $Label; - } - if (isset($meta['file']) && !isset($msg_meta['File'])) { - $msg_meta['File'] = $meta['file']; - } - if (isset($meta['line']) && !isset($msg_meta['Line'])) { - $msg_meta['Line'] = $meta['line']; - } - $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']'; - } - - $parts = explode("\n",chunk_split($msg, 5000, "\n")); - - for( $i=0 ; $i2) { - // Message needs to be split into multiple parts - $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, - (($i==0)?strlen($msg):'') - . '|' . $part . '|' - . (($isetHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, - strlen($part) . '|' . $part . '|'); - } - - $this->messageIndex++; - - if ($this->messageIndex > 99999) { - throw $this->newException('Maximum number (99,999) of messages reached!'); - } - } - } - - $this->setHeader('X-Wf-1-Index',$this->messageIndex-1); - - return true; - } - - /** - * Standardizes path for windows systems. - * - * @param string $Path - * @return string - */ - protected function _standardizePath($Path) - { - return preg_replace('/\\\\+/','/',$Path); - } - - /** - * Escape trace path for windows systems - * - * @param array $Trace - * @return array - */ - protected function _escapeTrace($Trace) - { - if (!$Trace) return $Trace; - for( $i=0 ; $i_escapeTraceFile($Trace[$i]['file']); - } - if (isset($Trace[$i]['args'])) { - $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']); - } - } - return $Trace; - } - - /** - * Escape file information of trace for windows systems - * - * @param string $File - * @return string - */ - protected function _escapeTraceFile($File) - { - /* Check if we have a windows filepath */ - if (strpos($File,'\\')) { - /* First strip down to single \ */ - - $file = preg_replace('/\\\\+/','\\',$File); - - return $file; - } - return $File; - } - - /** - * Check if headers have already been sent - * - * @param string $Filename - * @param integer $Linenum - */ - protected function headersSent(&$Filename, &$Linenum) - { - return headers_sent($Filename, $Linenum); - } - - /** - * Send header - * - * @param string $Name - * @param string $Value - */ - protected function setHeader($Name, $Value) - { - return header($Name.': '.$Value); - } - - /** - * Get user agent - * - * @return string|false - */ - protected function getUserAgent() - { - if (!isset($_SERVER['HTTP_USER_AGENT'])) return false; - return $_SERVER['HTTP_USER_AGENT']; - } - - /** - * Get all request headers - * - * @return array - */ - public static function getAllRequestHeaders() { - static $_cached_headers = false; - if($_cached_headers!==false) { - return $_cached_headers; - } - $headers = array(); - if(function_exists('getallheaders')) { - foreach( getallheaders() as $name => $value ) { - $headers[strtolower($name)] = $value; - } - } else { - foreach($_SERVER as $name => $value) { - if(substr($name, 0, 5) == 'HTTP_') { - $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value; - } - } - } - return $_cached_headers = $headers; - } - - /** - * Get a request header - * - * @return string|false - */ - protected function getRequestHeader($Name) - { - $headers = self::getAllRequestHeaders(); - if (isset($headers[strtolower($Name)])) { - return $headers[strtolower($Name)]; - } - return false; - } - - /** - * Returns a new exception - * - * @param string $Message - * @return Exception - */ - protected function newException($Message) - { - return new Exception($Message); - } - - /** - * Encode an object into a JSON string - * - * Uses PHP's jeson_encode() if available - * - * @param object $Object The object to be encoded - * @return string The JSON string - */ - public function jsonEncode($Object, $skipObjectEncode = false) - { - if (!$skipObjectEncode) { - $Object = $this->encodeObject($Object); - } - - if (function_exists('json_encode') - && $this->options['useNativeJsonEncode']!=false) { - - return json_encode($Object); - } else { - return $this->json_encode($Object); - } - } - - /** - * Encodes a table by encoding each row and column with encodeObject() - * - * @param array $Table The table to be encoded - * @return array - */ - protected function encodeTable($Table) - { - - if (!$Table) return $Table; - - $new_table = array(); - foreach($Table as $row) { - - if (is_array($row)) { - $new_row = array(); - - foreach($row as $item) { - $new_row[] = $this->encodeObject($item); - } - - $new_table[] = $new_row; - } - } - - return $new_table; - } - - /** - * Encodes an object including members with - * protected and private visibility - * - * @param Object $Object The object to be encoded - * @param int $Depth The current traversal depth - * @return array All members of the object - */ - protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1, $MaxDepth = 1) - { - if ($MaxDepth > $this->options['maxDepth']) { - return '** Max Depth ('.$this->options['maxDepth'].') **'; - } - - $return = array(); - - if (is_resource($Object)) { - - return '** '.(string)$Object.' **'; - - } else - if (is_object($Object)) { - - if ($ObjectDepth > $this->options['maxObjectDepth']) { - return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **'; - } - - foreach ($this->objectStack as $refVal) { - if ($refVal === $Object) { - return '** Recursion ('.get_class($Object).') **'; - } - } - array_push($this->objectStack, $Object); - - $return['__className'] = $class = get_class($Object); - $class_lower = strtolower($class); - - $reflectionClass = new ReflectionClass($class); - $properties = array(); - foreach( $reflectionClass->getProperties() as $property) { - $properties[$property->getName()] = $property; - } - - $members = (array)$Object; - - foreach( $properties as $plain_name => $property ) { - - $name = $raw_name = $plain_name; - if ($property->isStatic()) { - $name = 'static:'.$name; - } - if ($property->isPublic()) { - $name = 'public:'.$name; - } else - if ($property->isPrivate()) { - $name = 'private:'.$name; - $raw_name = "\0".$class."\0".$raw_name; - } else - if ($property->isProtected()) { - $name = 'protected:'.$name; - $raw_name = "\0".'*'."\0".$raw_name; - } - - if (!(isset($this->objectFilters[$class_lower]) - && is_array($this->objectFilters[$class_lower]) - && in_array($plain_name,$this->objectFilters[$class_lower]))) { - - if (array_key_exists($raw_name,$members) - && !$property->isStatic()) { - - $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1, $MaxDepth + 1); - - } else { - if (method_exists($property,'setAccessible')) { - $property->setAccessible(true); - $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); - } else - if ($property->isPublic()) { - $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); - } else { - $return[$name] = '** Need PHP 5.3 to get value **'; - } - } - } else { - $return[$name] = '** Excluded by Filter **'; - } - } - - // Include all members that are not defined in the class - // but exist in the object - foreach( $members as $raw_name => $value ) { - - $name = $raw_name; - - if ($name{0} == "\0") { - $parts = explode("\0", $name); - $name = $parts[2]; - } - - $plain_name = $name; - - if (!isset($properties[$name])) { - $name = 'undeclared:'.$name; - - if (!(isset($this->objectFilters[$class_lower]) - && is_array($this->objectFilters[$class_lower]) - && in_array($plain_name,$this->objectFilters[$class_lower]))) { - - $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1, $MaxDepth + 1); - } else { - $return[$name] = '** Excluded by Filter **'; - } - } - } - - array_pop($this->objectStack); - - } elseif (is_array($Object)) { - - if ($ArrayDepth > $this->options['maxArrayDepth']) { - return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **'; - } - - foreach ($Object as $key => $val) { - - // Encoding the $GLOBALS PHP array causes an infinite loop - // if the recursion is not reset here as it contains - // a reference to itself. This is the only way I have come up - // with to stop infinite recursion in this case. - if ($key=='GLOBALS' - && is_array($val) - && array_key_exists('GLOBALS',$val)) { - $val['GLOBALS'] = '** Recursion (GLOBALS) **'; - } - - $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1, $MaxDepth + 1); - } - } else { - if (self::is_utf8($Object)) { - return $Object; - } else { - return utf8_encode($Object); - } - } - return $return; - } - - /** - * Returns true if $string is valid UTF-8 and false otherwise. - * - * @param mixed $str String to be tested - * @return boolean - */ - protected static function is_utf8($str) - { - if(function_exists('mb_detect_encoding')) { - return (mb_detect_encoding($str) == 'UTF-8'); - } - $c=0; $b=0; - $bits=0; - $len=strlen($str); - for($i=0; $i<$len; $i++){ - $c=ord($str[$i]); - if ($c > 128){ - if (($c >= 254)) return false; - elseif ($c >= 252) $bits=6; - elseif ($c >= 248) $bits=5; - elseif ($c >= 240) $bits=4; - elseif ($c >= 224) $bits=3; - elseif ($c >= 192) $bits=2; - else return false; - if (($i+$bits) > $len) return false; - while($bits > 1){ - $i++; - $b=ord($str[$i]); - if ($b < 128 || $b > 191) return false; - $bits--; - } - } - } - return true; - } - - /** - * Converts to and from JSON format. - * - * JSON (JavaScript Object Notation) is a lightweight data-interchange - * format. It is easy for humans to read and write. It is easy for machines - * to parse and generate. It is based on a subset of the JavaScript - * Programming Language, Standard ECMA-262 3rd Edition - December 1999. - * This feature can also be found in Python. JSON is a text format that is - * completely language independent but uses conventions that are familiar - * to programmers of the C-family of languages, including C, C++, C#, Java, - * JavaScript, Perl, TCL, and many others. These properties make JSON an - * ideal data-interchange language. - * - * This package provides a simple encoder and decoder for JSON notation. It - * is intended for use with client-side Javascript applications that make - * use of HTTPRequest to perform server communication functions - data can - * be encoded into JSON notation for use in a client-side javascript, or - * decoded from incoming Javascript requests. JSON format is native to - * Javascript, and can be directly eval()'ed with no further parsing - * overhead - * - * All strings should be in ASCII or UTF-8 format! - * - * LICENSE: Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: Redistributions of source code must retain the - * above copyright notice, this list of conditions and the following - * disclaimer. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * @category - * @package Services_JSON - * @author Michal Migurski - * @author Matt Knapp - * @author Brett Stimmerman - * @author Christoph Dorn - * @copyright 2005 Michal Migurski - * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ - * @license http://www.opensource.org/licenses/bsd-license.php - * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 - */ - - - /** - * Keep a list of objects as we descend into the array so we can detect recursion. - */ - private $json_objectStack = array(); - - - /** - * convert a string from one UTF-8 char to one UTF-16 char - * - * Normally should be handled by mb_convert_encoding, but - * provides a slower PHP-only method for installations - * that lack the multibye string extension. - * - * @param string $utf8 UTF-8 character - * @return string UTF-16 character - * @access private - */ - private function json_utf82utf16($utf8) - { - // oh please oh please oh please oh please oh please - if (function_exists('mb_convert_encoding')) { - return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); - } - - switch(strlen($utf8)) { - case 1: - // this case should never be reached, because we are in ASCII range - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return $utf8; - - case 2: - // return a UTF-16 character from a 2-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0x07 & (ord($utf8{0}) >> 2)) - . chr((0xC0 & (ord($utf8{0}) << 6)) - | (0x3F & ord($utf8{1}))); - - case 3: - // return a UTF-16 character from a 3-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr((0xF0 & (ord($utf8{0}) << 4)) - | (0x0F & (ord($utf8{1}) >> 2))) - . chr((0xC0 & (ord($utf8{1}) << 6)) - | (0x7F & ord($utf8{2}))); - } - - // ignoring UTF-32 for now, sorry - return ''; - } - - /** - * encodes an arbitrary variable into JSON format - * - * @param mixed $var any number, boolean, string, array, or object to be encoded. - * see argument 1 to Services_JSON() above for array-parsing behavior. - * if var is a strng, note that encode() always expects it - * to be in ASCII or UTF-8 format! - * - * @return mixed JSON string representation of input var or an error if a problem occurs - * @access public - */ - private function json_encode($var) - { - - if (is_object($var)) { - if (in_array($var,$this->json_objectStack)) { - return '"** Recursion **"'; - } - } - - switch (gettype($var)) { - case 'boolean': - return $var ? 'true' : 'false'; - - case 'NULL': - return 'null'; - - case 'integer': - return (int) $var; - - case 'double': - case 'float': - return (float) $var; - - case 'string': - // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT - $ascii = ''; - $strlen_var = strlen($var); - - /* - * Iterate over every character in the string, - * escaping with a slash or encoding to UTF-8 where necessary - */ - for ($c = 0; $c < $strlen_var; ++$c) { - - $ord_var_c = ord($var{$c}); - - switch (true) { - case $ord_var_c == 0x08: - $ascii .= '\b'; - break; - case $ord_var_c == 0x09: - $ascii .= '\t'; - break; - case $ord_var_c == 0x0A: - $ascii .= '\n'; - break; - case $ord_var_c == 0x0C: - $ascii .= '\f'; - break; - case $ord_var_c == 0x0D: - $ascii .= '\r'; - break; - - case $ord_var_c == 0x22: - case $ord_var_c == 0x2F: - case $ord_var_c == 0x5C: - // double quote, slash, slosh - $ascii .= '\\'.$var{$c}; - break; - - case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): - // characters U-00000000 - U-0000007F (same as ASCII) - $ascii .= $var{$c}; - break; - - case (($ord_var_c & 0xE0) == 0xC0): - // characters U-00000080 - U-000007FF, mask 110XXXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, ord($var{$c + 1})); - $c += 1; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF0) == 0xE0): - // characters U-00000800 - U-0000FFFF, mask 1110XXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2})); - $c += 2; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF8) == 0xF0): - // characters U-00010000 - U-001FFFFF, mask 11110XXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3})); - $c += 3; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFC) == 0xF8): - // characters U-00200000 - U-03FFFFFF, mask 111110XX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4})); - $c += 4; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFE) == 0xFC): - // characters U-04000000 - U-7FFFFFFF, mask 1111110X - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4}), - ord($var{$c + 5})); - $c += 5; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - } - } - - return '"'.$ascii.'"'; - - case 'array': - /* - * As per JSON spec if any array key is not an integer - * we must treat the the whole array as an object. We - * also try to catch a sparsely populated associative - * array with numeric keys here because some JS engines - * will create an array with empty indexes up to - * max_index which can cause memory issues and because - * the keys, which may be relevant, will be remapped - * otherwise. - * - * As per the ECMA and JSON specification an object may - * have any string as a property. Unfortunately due to - * a hole in the ECMA specification if the key is a - * ECMA reserved word or starts with a digit the - * parameter is only accessible using ECMAScript's - * bracket notation. - */ - - // treat as a JSON object - if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { - - $this->json_objectStack[] = $var; - - $properties = array_map(array($this, 'json_name_value'), - array_keys($var), - array_values($var)); - - array_pop($this->json_objectStack); - - foreach($properties as $property) { - if ($property instanceof Exception) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - } - - $this->json_objectStack[] = $var; - - // treat it like a regular array - $elements = array_map(array($this, 'json_encode'), $var); - - array_pop($this->json_objectStack); - - foreach($elements as $element) { - if ($element instanceof Exception) { - return $element; - } - } - - return '[' . join(',', $elements) . ']'; - - case 'object': - $vars = self::encodeObject($var); - - $this->json_objectStack[] = $var; - - $properties = array_map(array($this, 'json_name_value'), - array_keys($vars), - array_values($vars)); - - array_pop($this->json_objectStack); - - foreach($properties as $property) { - if ($property instanceof Exception) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - - default: - return null; - } - } - - /** - * array-walking function for use in generating JSON-formatted name-value pairs - * - * @param string $name name of key to use - * @param mixed $value reference to an array element to be encoded - * - * @return string JSON-formatted name-value pair, like '"name":value' - * @access private - */ - private function json_name_value($name, $value) - { - // Encoding the $GLOBALS PHP array causes an infinite loop - // if the recursion is not reset here as it contains - // a reference to itself. This is the only way I have come up - // with to stop infinite recursion in this case. - if ($name=='GLOBALS' - && is_array($value) - && array_key_exists('GLOBALS',$value)) { - $value['GLOBALS'] = '** Recursion **'; - } - - $encoded_value = $this->json_encode($value); - - if ($encoded_value instanceof Exception) { - return $encoded_value; - } - - return $this->json_encode(strval($name)) . ':' . $encoded_value; - } - - /** - * @deprecated - */ - public function setProcessorUrl($URL) - { - trigger_error("The FirePHP::setProcessorUrl() method is no longer supported", E_USER_DEPRECATED); - } - - /** - * @deprecated - */ - public function setRendererUrl($URL) - { - trigger_error("The FirePHP::setRendererUrl() method is no longer supported", E_USER_DEPRECATED); - } -} diff --git a/htdocs/lib/assets/FirePHPCore/LICENSE b/htdocs/lib/assets/FirePHPCore/LICENSE deleted file mode 100644 index 3e390f9..0000000 --- a/htdocs/lib/assets/FirePHPCore/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -Software License Agreement (New BSD License) - -Copyright (c) 2006-2009, Christoph Dorn -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of Christoph Dorn nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/htdocs/lib/assets/FirePHPCore/fb.php b/htdocs/lib/assets/FirePHPCore/fb.php deleted file mode 100644 index 9ed9c42..0000000 --- a/htdocs/lib/assets/FirePHPCore/fb.php +++ /dev/null @@ -1,276 +0,0 @@ - - * @license http://www.opensource.org/licenses/bsd-license.php - * @package FirePHPCore - */ - -if(!class_exists('FirePHP')) { - require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'FirePHP.class.php'; -} - -/** - * Sends the given data to the FirePHP Firefox Extension. - * The data can be displayed in the Firebug Console or in the - * "Server" request tab. - * - * @see http://www.firephp.org/Wiki/Reference/Fb - * @param mixed $Object - * @return true - * @throws Exception - */ -function fb() -{ - $instance = FirePHP::getInstance(true); - - $args = func_get_args(); - return call_user_func_array(array($instance,'fb'),$args); -} - - -class FB -{ - /** - * Enable and disable logging to Firebug - * - * @see FirePHP->setEnabled() - * @param boolean $Enabled TRUE to enable, FALSE to disable - * @return void - */ - public static function setEnabled($Enabled) - { - $instance = FirePHP::getInstance(true); - $instance->setEnabled($Enabled); - } - - /** - * Check if logging is enabled - * - * @see FirePHP->getEnabled() - * @return boolean TRUE if enabled - */ - public static function getEnabled() - { - $instance = FirePHP::getInstance(true); - return $instance->getEnabled(); - } - - /** - * Specify a filter to be used when encoding an object - * - * Filters are used to exclude object members. - * - * @see FirePHP->setObjectFilter() - * @param string $Class The class name of the object - * @param array $Filter An array or members to exclude - * @return void - */ - public static function setObjectFilter($Class, $Filter) - { - $instance = FirePHP::getInstance(true); - $instance->setObjectFilter($Class, $Filter); - } - - /** - * Set some options for the library - * - * @see FirePHP->setOptions() - * @param array $Options The options to be set - * @return void - */ - public static function setOptions($Options) - { - $instance = FirePHP::getInstance(true); - $instance->setOptions($Options); - } - - /** - * Get options for the library - * - * @see FirePHP->getOptions() - * @return array The options - */ - public static function getOptions() - { - $instance = FirePHP::getInstance(true); - return $instance->getOptions(); - } - - /** - * Log object to firebug - * - * @see http://www.firephp.org/Wiki/Reference/Fb - * @param mixed $Object - * @return true - * @throws Exception - */ - public static function send() - { - $instance = FirePHP::getInstance(true); - $args = func_get_args(); - return call_user_func_array(array($instance,'fb'),$args); - } - - /** - * Start a group for following messages - * - * Options: - * Collapsed: [true|false] - * Color: [#RRGGBB|ColorName] - * - * @param string $Name - * @param array $Options OPTIONAL Instructions on how to log the group - * @return true - */ - public static function group($Name, $Options=null) - { - $instance = FirePHP::getInstance(true); - return $instance->group($Name, $Options); - } - - /** - * Ends a group you have started before - * - * @return true - * @throws Exception - */ - public static function groupEnd() - { - return self::send(null, null, FirePHP::GROUP_END); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::LOG - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public static function log($Object, $Label=null) - { - return self::send($Object, $Label, FirePHP::LOG); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::INFO - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public static function info($Object, $Label=null) - { - return self::send($Object, $Label, FirePHP::INFO); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::WARN - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public static function warn($Object, $Label=null) - { - return self::send($Object, $Label, FirePHP::WARN); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::ERROR - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public static function error($Object, $Label=null) - { - return self::send($Object, $Label, FirePHP::ERROR); - } - - /** - * Dumps key and variable to firebug server panel - * - * @see FirePHP::DUMP - * @param string $Key - * @param mixed $Variable - * @return true - * @throws Exception - */ - public static function dump($Key, $Variable) - { - return self::send($Variable, $Key, FirePHP::DUMP); - } - - /** - * Log a trace in the firebug console - * - * @see FirePHP::TRACE - * @param string $Label - * @return true - * @throws Exception - */ - public static function trace($Label) - { - return self::send($Label, FirePHP::TRACE); - } - - /** - * Log a table in the firebug console - * - * @see FirePHP::TABLE - * @param string $Label - * @param string $Table - * @return true - * @throws Exception - */ - public static function table($Label, $Table) - { - return self::send($Table, $Label, FirePHP::TABLE); - } - -} From db9326c956b3a1021c178372ee8b9ba9a8e14b07 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sat, 26 Jul 2014 10:54:17 -0700 Subject: [PATCH 06/35] User Class (not tested) --- htdocs/lib/User/Exceptions.php | 74 +++++++++++++++++++++++++++++++++ htdocs/lib/User/UserControl.php | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 htdocs/lib/User/Exceptions.php diff --git a/htdocs/lib/User/Exceptions.php b/htdocs/lib/User/Exceptions.php new file mode 100644 index 0000000..e38f461 --- /dev/null +++ b/htdocs/lib/User/Exceptions.php @@ -0,0 +1,74 @@ +userId = $userId; + parent::__construct($description); + } + + /** + * 取得輸入的資料庫系統名稱 + * @return string 錯誤訊息內容 + */ + public function getUserId() { + return $this->userId; + } +} + +// 使用者登入 ====================================================================== +/** + * 沒有找到此帳號 + * @since 3.0.0 + */ +class UserNoFoundException extends UserException { + public function __construct($userId) { + parent::__construct($userId, 'User: "'.$this->type.'" is no found.'); + } +} + + +/** + * 使用者登入密碼錯誤 + * @since 3.0.0 + */ +class UserPasswordErrException extends UserException { + public function __construct($userId) { + parent::__construct($userId, 'User: "'.$this->type.'" password is wrong.'); + } +} + +// 建立使用者 ====================================================================== +/** + * 已有重複的使用者名稱 + * @since 3.0.0 + */ +class UserIdExistException extends UserException { + public function __construct($userId) { + parent::__construct($userId, 'UserId: "'.$this->type.'" is exist.'); + } +} + diff --git a/htdocs/lib/User/UserControl.php b/htdocs/lib/User/UserControl.php index 5c5a5d9..7c39ffd 100644 --- a/htdocs/lib/User/UserControl.php +++ b/htdocs/lib/User/UserControl.php @@ -32,7 +32,7 @@ class UserControl { * @return bool 已有相同的帳號名稱 * @since 3.0.0 */ - public function isHave($userName) { + public function isExist($userName) { // TODO: Fill code in } From 125dfb1c7bc47010776b63eb0788f5b7e42562cb Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sun, 27 Jul 2014 10:59:01 -0700 Subject: [PATCH 07/35] Guard & UserException & Readme --- Guardfile | 6 +++- README.md | 51 ++++++++++++++++++++++++++++++++-- htdocs/index.php | 11 ++++++++ htdocs/lib/User/Exceptions.php | 12 ++++++-- 4 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 htdocs/index.php diff --git a/Guardfile b/Guardfile index e773bcb..cee967f 100644 --- a/Guardfile +++ b/Guardfile @@ -2,14 +2,18 @@ # More info at https://github.com/guard/guard#readme group :development do + gem 'guard' gem 'guard-livereload', require: false + gem 'guard-shell' end # Add files and commands to this file, like the example: # watch(%r{file/path}) { `command(s)` } # guard :shell do - watch(%r{htdocs/.+\.(php)}) { 'phpdoc -d ./htdocs/lib -t ./docs/' } + watch(%r{htdocs/.+\.(php)}) do + system 'phpdoc', '-d', './htdocs/lib', '-t', './docs/' + end end # LiveReload diff --git a/README.md b/README.md index d2c96cb..ffde88c 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,64 @@ 包含每位學生的學習資料、場地狀況、學習教材。以及處理學習路徑規劃。 -## 系統需求 +## 使用需求 * PHP5.3 以上,需要有以下Extension: * pdo_mysql * zip * MariaDB 5.5.31 (可用MySQL) +*** + +## 開發需求 +* 支援UTF-8編碼的文字編輯器 +* 開發文件產生器: phpdoc +* 自動化建置工具 + * guard(需有ruby環境) + * guard-shell + * guard-livereload + +## 建置開發環境 +### 安裝php, ruby 環境 +TODO: 代補,需有`gem`, `phar` + +### 安裝Guard + + gem install guard + gem install guard-shell + gem install guard-livereload + +#### 瀏覽器plugin安裝 +[LiveReload - browser extensions](http://feedback.livereload.com/knowledgebase/articles/86242-how-do-i-install-and-use-the-browser-extensions-) + +支援主流瀏覽器: + +* Firefox +* Chrome +* Safari + +### 安裝phpdoc + + pear channel-discover pear.phpdoc.org + pear install phpdoc/phpDocumentor + +## 自動化建置 +很簡單,只要下以下指令即可啟動 + + guard + +啟動後會監視專案內的`.php`檔案,一有任何變動將會 + +* phpdoc: 重新建立開發文件 +* livereload: 呼叫瀏覽器自動重新整理 + +#### 相關參考 +* +* ## 開發文件 已將整份專案使用[PHPDocumentor](http://www.phpdoc.org/)產生出[開發文件網站](docs/index.html) -產生指令: +產生指令(若有使用Guard的話可省略,會自動連同一起產生): phpdoc -d ./htdocs/lib -t ./docs/ diff --git a/htdocs/index.php b/htdocs/index.php new file mode 100644 index 0000000..b39c40d --- /dev/null +++ b/htdocs/index.php @@ -0,0 +1,11 @@ + + + + + Creating... + + +

    建置中~

    + + + \ No newline at end of file diff --git a/htdocs/lib/User/Exceptions.php b/htdocs/lib/User/Exceptions.php index e38f461..1b664d0 100644 --- a/htdocs/lib/User/Exceptions.php +++ b/htdocs/lib/User/Exceptions.php @@ -50,7 +50,6 @@ class UserNoFoundException extends UserException { } } - /** * 使用者登入密碼錯誤 * @since 3.0.0 @@ -61,6 +60,16 @@ class UserPasswordErrException extends UserException { } } +/** + * 此帳號未啟用 + * @since 3.0.0 + */ +class UserNoActivatedException extends UserException { + public function __construct($userId) { + parent::__construct($userId, 'User: "'.$this->type.'" is no activated.'); + } +} + // 建立使用者 ====================================================================== /** * 已有重複的使用者名稱 @@ -71,4 +80,3 @@ class UserIdExistException extends UserException { parent::__construct($userId, 'UserId: "'.$this->type.'" is exist.'); } } - From 79967cc2c3ab598ecc1623ae705a537273d0ae54 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 28 Jul 2014 21:38:25 -0700 Subject: [PATCH 08/35] init cli --- .gitignore | 2 +- cli/README.md | 4 ++++ cli/composer.json | 7 +++++++ cli/uelearning.php | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 cli/README.md create mode 100644 cli/composer.json create mode 100644 cli/uelearning.php diff --git a/.gitignore b/.gitignore index 30576f5..2d772a7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,4 @@ vendor/ # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file -# composer.lock +composer.lock diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000..dd3e602 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,4 @@ +後端伺服器 (指令界面) +=== + +這個... 現在沒有東西,就這樣 (逃 diff --git a/cli/composer.json b/cli/composer.json new file mode 100644 index 0000000..22c007b --- /dev/null +++ b/cli/composer.json @@ -0,0 +1,7 @@ +{ + "name": "uelearning", + "description": "UElearning", + "require": { + "symfony/console": "2.5.*" + } +} diff --git a/cli/uelearning.php b/cli/uelearning.php new file mode 100644 index 0000000..aefbddd --- /dev/null +++ b/cli/uelearning.php @@ -0,0 +1,18 @@ +#!/usr/bin/env php +run(); +?> \ No newline at end of file From eb56544d1d25a7a2d94715feb8a840f709687301 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Tue, 29 Jul 2014 12:01:10 -0700 Subject: [PATCH 09/35] Fix Database class --- htdocs/lib/Database/Database.php | 9 +++++++-- htdocs/lib/Database/MySQLDB.php | 11 +++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/htdocs/lib/Database/Database.php b/htdocs/lib/Database/Database.php index da13683..54d2b96 100644 --- a/htdocs/lib/Database/Database.php +++ b/htdocs/lib/Database/Database.php @@ -15,7 +15,8 @@ use UElearning\Database\Exception; /** * 資料庫操作抽象類別 * - * 請根據一個資料表創建一個類別,並繼承此類別。所有對於資料表的操作(包含查詢、新增、修改、刪除),一律使用新創已繼承的類別物件。 + * 請根據一個資料表創建一個類別,並繼承此類別。 + * 所有對於資料表的操作(包含查詢、新增、修改、刪除),一律使用新創已繼承的類別物件。 * * 基本的操作方式例如: * @@ -136,7 +137,11 @@ abstract class Database { // 檢查是否有支援所設定的DBMS if($this->db_type == 'mysql') { - $this->connDB = new MySQLDB($this->db_name, $this->db_host, $this->db_port, $this->db_user, $this->db_passwd); + $this->connDB = new MySQLDB($this->db_name + , $this->db_host + , $this->db_port + , $this->db_user + , $this->db_passwd); } else { throw new Exception\DatabaseNoSupportException($this->db_type); diff --git a/htdocs/lib/Database/MySQLDB.php b/htdocs/lib/Database/MySQLDB.php index daa8fa7..8f6035d 100644 --- a/htdocs/lib/Database/MySQLDB.php +++ b/htdocs/lib/Database/MySQLDB.php @@ -33,12 +33,13 @@ class MySQLDB extends PDO { * @since 3.0.0 */ public function __construct($dbname, $host, $port, $user, $passwd){ - parent::__construct("mysql:dbname=".$dbname.";host:".$host."port=".$port."; - charset=utf8", DB_USER, DB_PASS); + parent::__construct('mysql:dbname='.$dbname + .';host:'.$host.';port='.$port + .';charset=utf8', DB_USER, DB_PASS); //配合PHP< 5.3.6 PDO沒有charset用的 //參考: http://gdfan1114.wordpress.com/2013/06/24/php-5-3-6-%E7%89%88-pdo-%E9%85%8D%E5%90%88%E5%AD%98%E5%8F%96%E8%B3%87%E6%96%99%E5%BA%AB%E6%99%82%E7%9A%84%E4%B8%AD%E6%96%87%E5%95%8F%E9%A1%8C/ - $this->exec("set names utf8"); + $this->exec('set names utf8'); } @@ -58,7 +59,9 @@ class MySQLDB extends PDO { public function ErrorMsg(){ $err = parent ::errorinfo(); if( $err[0]!='00000' ){ - return array('errorCode'=>$err[0],'number'=>$err[1],'message'=>$err[2]); + return array('errorCode'=>$err[0] + ,'number'=>$err[1] + ,'message'=>$err[2]); }else{ return null; } From b3c5a093493229d100d5dff0105758420187ff14 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 4 Aug 2014 17:37:04 -0700 Subject: [PATCH 10/35] add UserSession --- htdocs/lib/User/UserControl.php | 13 +--- htdocs/lib/User/UserSession.php | 113 ++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 htdocs/lib/User/UserSession.php diff --git a/htdocs/lib/User/UserControl.php b/htdocs/lib/User/UserControl.php index 7c39ffd..48bdffa 100644 --- a/htdocs/lib/User/UserControl.php +++ b/htdocs/lib/User/UserControl.php @@ -35,16 +35,5 @@ class UserControl { public function isExist($userName) { // TODO: Fill code in } - - /** - * 使用者登入 - * @param string $userId 帳號名稱 - * @param string $password 密碼 - * @return string 登入session token - * @since 3.0.0 - */ - public function login($userId, $password) { - // TODO: Fill code in - // 如果登入錯誤,就丟例外 - } + } \ No newline at end of file diff --git a/htdocs/lib/User/UserSession.php b/htdocs/lib/User/UserSession.php new file mode 100644 index 0000000..9f39064 --- /dev/null +++ b/htdocs/lib/User/UserSession.php @@ -0,0 +1,113 @@ + + * @version 2.0.0 + * @package UElearning + * @subpackage User + */ +class UserSession { + + /** + * 使用者登入 + * @param string $userId 帳號名稱 + * @param string $password 密碼 + * @return string 登入session token + * @since 2.0.0 + */ + public function login($userId, $password) { + // TODO: Fill code in + // 如果登入錯誤,就丟例外 + } + + // ======================================================================== + + /** + * 使用者登出 + * @param string $token 登入階段token + * @since 2.0.0 + */ + public function logout($token) { + // TODO: Fill code in + } + + /** + * 將其他已登入的裝置登出 + * @param string $token 登入階段token + * @since 2.0.0 + */ + public function logoutOtherSession($token) { + // TODO: Fill code in + } + + + /** + * 取得使用者物件 + * @param string $token 登入階段token + * @return User 使用者物件 + * @since 2.0.0 + */ + public function getUser($token) { + // TODO: Fill code in + } + + /** + * 取得登入資訊 + * @param string $token 登入階段token + * @return Array 此登入階段資訊 + * @since 2.0.0 + */ + public function getTokenInfo($token) { + // TODO: Fill code in + } + + // ======================================================================== + + /** + * 取得所有此使用者已登入的登入階段資訊 + * @param string $userId 使用者帳號名稱 + * @return Array 已登入的所有登入階段資訊 + * @since 2.0.0 + */ + public function getUserLoginInfo($userId) { + // TODO: Fill code in + } + + /** + * 取得此使用者登入的裝置數 + * @param string $userId 使用者帳號名稱 + * @return int 所有以登入的數量 + * @since 2.0.0 + */ + public function getUserLoginTotal($userId) { + // TODO: Fill code in + } + + /** + * 取得所有此使用者全部的登入階段資訊 + * + * 用於查詢登入紀錄的時候使用 + * @param string $userId 使用者帳號名稱 + * @return Array 已登入的所有登入階段資訊 + * @since 2.0.0 + */ + public function getUserAllInfo($userId) { + // TODO: Fill code in + } + + /** + * 將此使用者全部登入階段登出 + * @param string $userId 使用者帳號名稱 + * @since 2.0.0 + */ + public function logoutUserAllSession($userId) { + // TODO: Fill code in + } +} \ No newline at end of file From d3001ecc28b4b279c3b0bda2adf6cc5afb198727 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 4 Aug 2014 17:52:50 -0700 Subject: [PATCH 11/35] Fix All Comment --- htdocs/lib/Config/Exceptions.php | 13 ++++++------ htdocs/lib/Database/DBAdmin.php | 9 ++++----- htdocs/lib/Database/DBUser.php | 9 ++++----- htdocs/lib/Database/Database.php | 8 ++++---- htdocs/lib/Database/Exceptions.php | 17 ++++++++-------- htdocs/lib/Database/MySQLDB.php | 5 +++-- htdocs/lib/User/ClassGroup.php | 7 +++++++ htdocs/lib/User/ClassGroupAdmin.php | 7 +++++++ htdocs/lib/User/Exceptions.php | 31 +++++++++++++++++++++-------- htdocs/lib/User/User.php | 10 +++++----- htdocs/lib/User/UserControl.php | 16 +++++++-------- htdocs/lib/User/UserGroup.php | 7 +++++++ htdocs/lib/User/UserGroupAdmin.php | 7 +++++++ htdocs/lib/User/UserSession.php | 4 ++-- 14 files changed, 95 insertions(+), 55 deletions(-) diff --git a/htdocs/lib/Config/Exceptions.php b/htdocs/lib/Config/Exceptions.php index 057302e..da28aee 100644 --- a/htdocs/lib/Config/Exceptions.php +++ b/htdocs/lib/Config/Exceptions.php @@ -1,11 +1,10 @@ -type.'" is no found.'); } @@ -55,6 +58,10 @@ class UserNoFoundException extends UserException { * @since 3.0.0 */ class UserPasswordErrException extends UserException { + /** + * 沒有找到此帳號 + * @param string $userId 輸入的使用者名稱 + */ public function __construct($userId) { parent::__construct($userId, 'User: "'.$this->type.'" password is wrong.'); } @@ -65,6 +72,10 @@ class UserPasswordErrException extends UserException { * @since 3.0.0 */ class UserNoActivatedException extends UserException { + /** + * 此帳號未啟用 + * @param string $userId 輸入的使用者名稱 + */ public function __construct($userId) { parent::__construct($userId, 'User: "'.$this->type.'" is no activated.'); } @@ -76,6 +87,10 @@ class UserNoActivatedException extends UserException { * @since 3.0.0 */ class UserIdExistException extends UserException { + /** + * 已有重複的使用者名稱 + * @param string $userId 輸入的使用者名稱 + */ public function __construct($userId) { parent::__construct($userId, 'UserId: "'.$this->type.'" is exist.'); } diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php index 08fa72b..78cb79a 100644 --- a/htdocs/lib/User/User.php +++ b/htdocs/lib/User/User.php @@ -1,8 +1,8 @@ - - * @version 3.0 + * @version 2.0.0 * @package UElearning * @subpackage User */ @@ -19,7 +17,7 @@ class UserControl { /** * 建立使用者 - * @since 3.0.0 + * @since 2.0.0 */ public function create() { // TODO: Fill code in @@ -30,7 +28,7 @@ class UserControl { * * @param string $userName 帳號名稱 * @return bool 已有相同的帳號名稱 - * @since 3.0.0 + * @since 2.0.0 */ public function isExist($userName) { // TODO: Fill code in diff --git a/htdocs/lib/User/UserGroup.php b/htdocs/lib/User/UserGroup.php index e69de29..857b05f 100644 --- a/htdocs/lib/User/UserGroup.php +++ b/htdocs/lib/User/UserGroup.php @@ -0,0 +1,7 @@ + Date: Mon, 4 Aug 2014 18:36:27 -0700 Subject: [PATCH 12/35] =?UTF-8?q?=E7=89=88=E8=99=9F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/lib/Database/DBAdmin.php | 2 +- htdocs/lib/Database/DBUser.php | 2 +- htdocs/lib/Database/Database.php | 8 ++++---- htdocs/lib/Database/Exceptions.php | 2 +- htdocs/lib/Database/MySQLDB.php | 6 +++--- htdocs/lib/User/Exceptions.php | 10 +++++----- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/htdocs/lib/Database/DBAdmin.php b/htdocs/lib/Database/DBAdmin.php index f604982..37db483 100644 --- a/htdocs/lib/Database/DBAdmin.php +++ b/htdocs/lib/Database/DBAdmin.php @@ -50,7 +50,7 @@ require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; * } * * @author Yuan Chiu - * @version 3.0 + * @version 2.0.0 * @package UElearning * @subpackage Database */ diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index b239da5..6a58f76 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -17,7 +17,7 @@ require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; * * * @author Yuan Chiu - * @version 3.0 + * @version 2.0.0 * @package UElearning * @subpackage Database */ diff --git a/htdocs/lib/Database/Database.php b/htdocs/lib/Database/Database.php index a4729dd..9317fbc 100644 --- a/htdocs/lib/Database/Database.php +++ b/htdocs/lib/Database/Database.php @@ -34,7 +34,7 @@ use UElearning\Database\Exception; * 實際範例可參考 `DBAdmin` 類別的說明文件 * * @author Yuan Chiu - * @version 3.0 + * @version 2.0.0 * @package UElearning * @subpackage Database */ @@ -111,7 +111,7 @@ abstract class Database { * * @throws UElearning\Database\Exception\DatabaseNoSupportException * @author Yuan Chiu - * @since 3.0.0 + * @since 2.0.0 */ public function __construct($conf = null) { @@ -155,7 +155,7 @@ abstract class Database { * @return string 完整的資料表名稱 * * @author Yuan Chiu - * @since 3.0.0 + * @since 2.0.0 */ public function table($tableName) { return $this->db_prefix.$tableName; @@ -164,7 +164,7 @@ abstract class Database { /** * 測試資料庫有無連接成功 * - * @since 3.0.0 + * @since 2.0.0 */ public function connectTest() { // TODO: Fill code in diff --git a/htdocs/lib/Database/Exceptions.php b/htdocs/lib/Database/Exceptions.php index 3a7dcd0..dff099d 100644 --- a/htdocs/lib/Database/Exceptions.php +++ b/htdocs/lib/Database/Exceptions.php @@ -7,7 +7,7 @@ namespace UElearning\Database\Exception; /** * 沒有支援的資料庫系統例外 - * @since 3.0.0 + * @since 2.0.0 */ class DatabaseNoSupportException extends \UnexpectedValueException { diff --git a/htdocs/lib/Database/MySQLDB.php b/htdocs/lib/Database/MySQLDB.php index 5aaabd8..9003f5b 100644 --- a/htdocs/lib/Database/MySQLDB.php +++ b/htdocs/lib/Database/MySQLDB.php @@ -15,7 +15,7 @@ use \PDO; * * @extends PDO * @author Yuan Chiu - * @version 3.0 + * @version 2.0.0 * @see https://github.com/shuliu/myPDO * @package UElearning * @subpackage Database @@ -31,7 +31,7 @@ class MySQLDB extends PDO { * @param string $user 資料庫伺服器帳號 * @param string $passwd 資料庫伺服器密碼 * @author Yuan Chiu - * @since 3.0.0 + * @since 2.0.0 */ public function __construct($dbname, $host, $port, $user, $passwd){ parent::__construct('mysql:dbname='.$dbname @@ -53,7 +53,7 @@ class MySQLDB extends PDO { * @access public * @return array 錯誤訊息 * - * @since 2013.8.6 + * @since 2.0.0 * @author shuliu * @see https://github.com/shuliu/myPDO/blob/master/PDO.class.php */ diff --git a/htdocs/lib/User/Exceptions.php b/htdocs/lib/User/Exceptions.php index 86f8472..7cd1119 100644 --- a/htdocs/lib/User/Exceptions.php +++ b/htdocs/lib/User/Exceptions.php @@ -7,7 +7,7 @@ namespace UElearning\User\Exception; /** * 使用者帳號例外 - * @since 3.0.0 + * @since 2.0.0 * @package UElearning * @subpackage User */ @@ -41,7 +41,7 @@ abstract class UserException extends \UnexpectedValueException { // 使用者登入 ====================================================================== /** * 沒有找到此帳號 - * @since 3.0.0 + * @since 2.0.0 */ class UserNoFoundException extends UserException { /** @@ -55,7 +55,7 @@ class UserNoFoundException extends UserException { /** * 使用者登入密碼錯誤 - * @since 3.0.0 + * @since 2.0.0 */ class UserPasswordErrException extends UserException { /** @@ -69,7 +69,7 @@ class UserPasswordErrException extends UserException { /** * 此帳號未啟用 - * @since 3.0.0 + * @since 2.0.0 */ class UserNoActivatedException extends UserException { /** @@ -84,7 +84,7 @@ class UserNoActivatedException extends UserException { // 建立使用者 ====================================================================== /** * 已有重複的使用者名稱 - * @since 3.0.0 + * @since 2.0.0 */ class UserIdExistException extends UserException { /** From e194a5caa8a9f319193cd709c9f516265bd5719b Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 4 Aug 2014 23:38:54 -0700 Subject: [PATCH 13/35] =?UTF-8?q?Add=20SQL=E8=A6=8F=E5=8A=83=E5=BE=8C?= =?UTF-8?q?=E7=9A=84=E5=8C=AF=E5=87=BA=E5=82=99=E4=BB=BD=E6=AA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/UElearning_2014_08_04.sql | 244 ++++++++++++++++++++++++++++++++++ sql/here | 0 2 files changed, 244 insertions(+) create mode 100644 sql/UElearning_2014_08_04.sql delete mode 100644 sql/here diff --git a/sql/UElearning_2014_08_04.sql b/sql/UElearning_2014_08_04.sql new file mode 100644 index 0000000..4bed1ce --- /dev/null +++ b/sql/UElearning_2014_08_04.sql @@ -0,0 +1,244 @@ +-- phpMyAdmin SQL Dump +-- version 4.1.6 +-- http://www.phpmyadmin.net +-- +-- 主機: localhost +-- 產生時間: 2014 年 08 月 05 日 08:36 +-- 伺服器版本: 5.6.16 +-- PHP 版本: 5.5.9 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; + +-- +-- 資料庫: `UElearning` +-- + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__ABelong` +-- + +CREATE TABLE IF NOT EXISTS `chu__ABelong` ( + `TID` int(10) unsigned NOT NULL, + `AID` int(10) unsigned NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__AGroup` +-- + +CREATE TABLE IF NOT EXISTS `chu__AGroup` ( + `GID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `GName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `GMemo` tinytext COLLATE utf8_unicode_ci, + PRIMARY KEY (`GID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__Area` +-- + +CREATE TABLE IF NOT EXISTS `chu__Area` ( + `AID` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '區域編號', + `AName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '區域名稱', + `AMapID` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '區域地圖編號', + `AIntroduction` tinytext COLLATE utf8_unicode_ci, + PRIMARY KEY (`AID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__CGroup` +-- + +CREATE TABLE IF NOT EXISTS `chu__CGroup` ( + `CID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `CName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `CMemo` tinytext COLLATE utf8_unicode_ci, + PRIMARY KEY (`CID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__Edge` +-- + +CREATE TABLE IF NOT EXISTS `chu__Edge` ( + `Ti` int(11) NOT NULL, + `Tj` int(11) NOT NULL, + `MoveTime` int(4) NOT NULL COMMENT '移動時間(分鐘)', + `Destance` int(11) NOT NULL COMMENT '距離(M)' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__LearnActivity` +-- + +CREATE TABLE IF NOT EXISTS `chu__LearnActivity` ( + `LsID` int(10) NOT NULL, + `ThID` int(10) NOT NULL COMMENT '主題編號', + `CID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '班級名稱', + `StartTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '開始時間', + `Delay` int(11) NOT NULL COMMENT '實際狀態延誤(分)', + PRIMARY KEY (`LsID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__Material` +-- + +CREATE TABLE IF NOT EXISTS `chu__Material` ( + `MID` int(10) unsigned NOT NULL COMMENT '教材內部編號', + `TID` int(10) unsigned NOT NULL COMMENT '標的內部編號', + `MMode` int(1) NOT NULL DEFAULT '0' COMMENT '教材模式', + `MUrl` varchar(1000) COLLATE utf8_unicode_ci NOT NULL COMMENT '教材檔案路徑', + PRIMARY KEY (`MID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__Recommand` +-- + +CREATE TABLE IF NOT EXISTS `chu__Recommand` ( + `TID` int(3) NOT NULL COMMENT '標的內部編號', + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '使用者帳號', + `gradation` int(11) NOT NULL COMMENT '系統推薦標地順序' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__Study` +-- + +CREATE TABLE IF NOT EXISTS `chu__Study` ( + `SID` int(10) NOT NULL AUTO_INCREMENT, + `TID` int(10) NOT NULL COMMENT '標的內部編號', + `UID` int(30) NOT NULL COMMENT '使用者名稱', + `LMode` int(11) NOT NULL COMMENT '學習導引模式', + `MMode` int(11) NOT NULL COMMENT '教材模式', + `In_TargetTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '進入標的時間', + `Out_TargetTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '離開標的時間', + PRIMARY KEY (`SID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__StudyQuestion` +-- + +CREATE TABLE IF NOT EXISTS `chu__StudyQuestion` ( + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `TID` int(10) NOT NULL, + `QID` int(11) NOT NULL, + `UAns` int(11) NOT NULL, + `CAns` int(11) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__Target` +-- + +CREATE TABLE IF NOT EXISTS `chu__Target` ( + `TID` int(10) unsigned NOT NULL COMMENT '標的內部編號', + `TNum` int(10) DEFAULT NULL COMMENT '標的地圖上的編號', + `TName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '標的名稱', + `TMapID` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地圖圖檔名稱', + `TLearnTime` int(4) unsigned NOT NULL COMMENT '預估此標的應該學習的時間', + `PLj` int(11) unsigned NOT NULL COMMENT '學習標的的人數限制', + `Mj` int(11) unsigned DEFAULT NULL COMMENT '目前人數', + `S` int(11) unsigned DEFAULT NULL COMMENT '學習標的飽和率上限', + `Fi` int(11) DEFAULT NULL COMMENT '學習標的滿額指標', + PRIMARY KEY (`TID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__TBelong` +-- + +CREATE TABLE IF NOT EXISTS `chu__TBelong` ( + `TID` int(10) NOT NULL, + `ThID` int(10) NOT NULL, + `Weights` int(3) NOT NULL COMMENT '當次學習主題的某一個學習標的之權重' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__Theme` +-- + +CREATE TABLE IF NOT EXISTS `chu__Theme` ( + `ThID` int(10) unsigned NOT NULL AUTO_INCREMENT, + `ThName` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '主題名稱', + `ThLearnTotal` int(4) NOT NULL COMMENT '學習此主題要花的總時間(m)', + `ThIntroduction` tinytext COLLATE utf8_unicode_ci COMMENT '介紹', + PRIMARY KEY (`ThID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__User` +-- + +CREATE TABLE IF NOT EXISTS `chu__User` ( + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '使用者帳號', + `UPassword` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '密碼', + `GID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '使用者群組', + `CID` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '使用者班級', + `UEnabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '帳號啟用狀態', + `UBuild_Time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '帳號建立時間', + `LMode` enum('line-learn','harf-line-learn','non-line-learn') COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '學習導引模式', + `MMode` int(11) DEFAULT NULL COMMENT '教材模式', + `UNickname` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '暱稱', + `UReal_Name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '真實姓名', + `UEmail` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '使用者email', + `UMemo` tinytext COLLATE utf8_unicode_ci COMMENT '備註', + PRIMARY KEY (`UID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- 資料表結構 `chu__UserSession` +-- + +CREATE TABLE IF NOT EXISTS `chu__UserSession` ( + `UsID` int(10) unsigned NOT NULL AUTO_INCREMENT, + `UToken` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '此登入階段的token', + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `UAgent` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '使用哪個裝置登入', + `ULoginDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登入時間', + `ULogoutDate` timestamp NULL DEFAULT NULL COMMENT '登出時間', + PRIMARY KEY (`UsID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/sql/here b/sql/here deleted file mode 100644 index e69de29..0000000 From af0d8c49be2b2befc9c4c233872e454c423846d0 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sat, 16 Aug 2014 21:51:13 -0700 Subject: [PATCH 14/35] =?UTF-8?q?=E8=B3=87=E6=96=99=E5=BA=AB=E7=A8=8B?= =?UTF-8?q?=E5=BC=8F=E7=A2=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/lib/Database/DBAdmin.php | 158 ++++++++++++++++++++++++++++--- htdocs/lib/Database/DBUser.php | 5 - htdocs/lib/Database/Database.php | 16 ++-- htdocs/lib/Database/MySQLDB.php | 2 +- tests/InstallTest.php | 34 +++++++ 5 files changed, 188 insertions(+), 27 deletions(-) create mode 100644 tests/InstallTest.php diff --git a/htdocs/lib/Database/DBAdmin.php b/htdocs/lib/Database/DBAdmin.php index 37db483..1f7de8c 100644 --- a/htdocs/lib/Database/DBAdmin.php +++ b/htdocs/lib/Database/DBAdmin.php @@ -56,24 +56,156 @@ require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; */ class DBAdmin extends Database { - /** - * 建立資料庫 - * - * 在資料庫系統內建立一個資料庫。 - * (注意!需有建立資料庫的權限) - * - */ - public function createDB() { - // TODO: Fill code in - - } - /** * 建立所有所需的資料表 * + * @since 2.0.0 */ public function createAllTable() { - // TODO: Fill code in + // 使用的資料庫系統為MySQL + if($this->db_type == 'mysql') { + + // 所有要跑的SQL指令陣列 + $execSql = array( + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."ABelong` ( + `TID` int(10) unsigned NOT NULL, + `AID` int(10) unsigned NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."AGroup` ( + `GID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `GName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `GMemo` tinytext COLLATE utf8_unicode_ci, + PRIMARY KEY (`GID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."Area` ( + `AID` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '區域編號', + `AName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '區域名稱', + `AMapID` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '區域地圖編號', + `AIntroduction` tinytext COLLATE utf8_unicode_ci, + PRIMARY KEY (`AID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."CGroup` ( + `CID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `CName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, + `CMemo` tinytext COLLATE utf8_unicode_ci, + PRIMARY KEY (`CID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."Edge` ( + `Ti` int(11) NOT NULL, + `Tj` int(11) NOT NULL, + `MoveTime` int(4) NOT NULL COMMENT '移動時間(分鐘)', + `Destance` int(11) NOT NULL COMMENT '距離(M)' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."LearnActivity` ( + `LsID` int(10) NOT NULL, + `ThID` int(10) NOT NULL COMMENT '主題編號', + `CID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '班級名稱', + `StartTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '開始時間', + `Delay` int(11) NOT NULL COMMENT '實際狀態延誤(分)', + PRIMARY KEY (`LsID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."Material` ( + `MID` int(10) unsigned NOT NULL COMMENT '教材內部編號', + `TID` int(10) unsigned NOT NULL COMMENT '標的內部編號', + `MMode` int(1) NOT NULL DEFAULT '0' COMMENT '教材模式', + `MUrl` varchar(1000) COLLATE utf8_unicode_ci NOT NULL COMMENT '教材檔案路徑', + PRIMARY KEY (`MID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."Recommand` ( + `TID` int(3) NOT NULL COMMENT '標的內部編號', + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '使用者帳號', + `gradation` int(11) NOT NULL COMMENT '系統推薦標地順序' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."Study` ( + `SID` int(10) NOT NULL AUTO_INCREMENT, + `TID` int(10) NOT NULL COMMENT '標的內部編號', + `UID` int(30) NOT NULL COMMENT '使用者名稱', + `LMode` int(11) NOT NULL COMMENT '學習導引模式', + `MMode` int(11) NOT NULL COMMENT '教材模式', + `In_TargetTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '進入標的時間', + `Out_TargetTime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '離開標的時間', + PRIMARY KEY (`SID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."StudyQuestion` ( + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `TID` int(10) NOT NULL, + `QID` int(11) NOT NULL, + `UAns` int(11) NOT NULL, + `CAns` int(11) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."Target` ( + `TID` int(10) unsigned NOT NULL COMMENT '標的內部編號', + `TNum` int(10) DEFAULT NULL COMMENT '標的地圖上的編號', + `TName` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '標的名稱', + `TMapID` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地圖圖檔名稱', + `TLearnTime` int(4) unsigned NOT NULL COMMENT '預估此標的應該學習的時間', + `PLj` int(11) unsigned NOT NULL COMMENT '學習標的的人數限制', + `Mj` int(11) unsigned DEFAULT NULL COMMENT '目前人數', + `S` int(11) unsigned DEFAULT NULL COMMENT '學習標的飽和率上限', + `Fi` int(11) DEFAULT NULL COMMENT '學習標的滿額指標', + PRIMARY KEY (`TID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."TBelong` ( + `TID` int(10) NOT NULL, + `ThID` int(10) NOT NULL, + `Weights` int(3) NOT NULL COMMENT '當次學習主題的某一個學習標的之權重' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."Theme` ( + `ThID` int(10) unsigned NOT NULL AUTO_INCREMENT, + `ThName` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '主題名稱', + `ThLearnTotal` int(4) NOT NULL COMMENT '學習此主題要花的總時間(m)', + `ThIntroduction` tinytext COLLATE utf8_unicode_ci COMMENT '介紹', + PRIMARY KEY (`ThID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."User` ( + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '使用者帳號', + `UPassword` varchar(100) COLLATE utf8_unicode_ci NOT NULL COMMENT '密碼', + `GID` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '使用者群組', + `CID` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '使用者班級', + `UEnabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '帳號啟用狀態', + `UBuild_Time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '帳號建立時間', + `LMode` enum('line-learn','harf-line-learn','non-line-learn') COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '學習導引模式', + `MMode` int(11) DEFAULT NULL COMMENT '教材模式', + `UNickname` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '暱稱', + `UReal_Name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '真實姓名', + `UEmail` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '使用者email', + `UMemo` tinytext COLLATE utf8_unicode_ci COMMENT '備註', + PRIMARY KEY (`UID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;", + +"CREATE TABLE IF NOT EXISTS `".$this->db_prefix."UserSession` ( + `UsID` int(10) unsigned NOT NULL AUTO_INCREMENT, + `UToken` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '此登入階段的token', + `UID` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `UAgent` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '使用哪個裝置登入', + `ULoginDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登入時間', + `ULogoutDate` timestamp NULL DEFAULT NULL COMMENT '登出時間', + PRIMARY KEY (`UsID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;" + ); + + // 執行此SQL指令 + foreach ($execSql as $value ){ + $this->connDB->exec($value); + }; + } + else { + throw new Exception\DatabaseNoSupportException($this->db_type); + } } } \ No newline at end of file diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index 6a58f76..9c1def8 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -22,11 +22,6 @@ require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; * @subpackage Database */ class DBUser extends Database { - /** - * 資料表名稱 - * @type string - */ - private $form_name = 'user'; } \ No newline at end of file diff --git a/htdocs/lib/Database/Database.php b/htdocs/lib/Database/Database.php index 9317fbc..6eff00c 100644 --- a/htdocs/lib/Database/Database.php +++ b/htdocs/lib/Database/Database.php @@ -48,43 +48,43 @@ abstract class Database { * * @type string */ - private $db_type; + protected $db_type; /** * 資料庫伺服器位址 * @type string */ - private $db_host; + protected $db_host; /** * 資料庫伺服器連結埠 * @type string */ - private $db_port; + protected $db_port; /** * 資料庫帳號 * @type string */ - private $db_user; + protected $db_user; /** * 資料庫密碼 * @type string */ - private $db_passwd; + protected $db_passwd; /** * 資料庫名稱 * @type string */ - private $db_name; + protected $db_name; /** * 資料表前綴字元 * @type string */ - private $db_prefix; + protected $db_prefix; // ------------------------------------------------------------------------ @@ -92,7 +92,7 @@ abstract class Database { * 資料庫連結物件 * @type UElearning\Database\PDODB */ - private $connDB; + protected $connDB; // ======================================================================== diff --git a/htdocs/lib/Database/MySQLDB.php b/htdocs/lib/Database/MySQLDB.php index 9003f5b..89be3dd 100644 --- a/htdocs/lib/Database/MySQLDB.php +++ b/htdocs/lib/Database/MySQLDB.php @@ -57,7 +57,7 @@ class MySQLDB extends PDO { * @author shuliu * @see https://github.com/shuliu/myPDO/blob/master/PDO.class.php */ - public function ErrorMsg(){ + public function errorMsg(){ $err = parent ::errorinfo(); if( $err[0]!='00000' ){ return array('errorCode'=>$err[0] diff --git a/tests/InstallTest.php b/tests/InstallTest.php new file mode 100644 index 0000000..383899d --- /dev/null +++ b/tests/InstallTest.php @@ -0,0 +1,34 @@ + + */ +namespace UElearning; + +require_once __DIR__.'/../htdocs/config.php'; +require_once UELEARNING_LIB_ROOT.'Database/DBAdmin.php'; + +class InstallTest extends \PHPUnit_Framework_TestCase +{ + + /** + * 測試安裝初始化資料庫 + */ + public function testInstallDatabase() + { + + try { + // 建立資料庫管理物件 + $dbAdmin = new Database\DBAdmin(); + + // 建立所有所需的資料表 + $dbAdmin->createAllTable(); + } + // 若設定的DBMS不被支援 則丟出例外 + catch (Database\Exception\DatabaseNoSupportException $e) { + throw $e; + } + } +} \ No newline at end of file From b3bc9602f5c566edd1ae91d582968cb9c009b668 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sat, 16 Aug 2014 21:57:14 -0700 Subject: [PATCH 15/35] =?UTF-8?q?=E6=95=B4=E9=A0=93=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E6=AA=94=20=E8=B7=AF=E5=BE=91=E4=BD=8D=E7=BD=AE=E8=A8=98?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 將所有路徑相關常數改成最後尾端不含`/`字元 --- htdocs/config.sample.php | 19 +++++++++---------- htdocs/lib/Database/DBAdmin.php | 4 ++-- htdocs/lib/Database/DBUser.php | 4 ++-- htdocs/lib/Database/Database.php | 4 ++-- tests/InstallTest.php | 2 +- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/htdocs/config.sample.php b/htdocs/config.sample.php index a6e33d2..8f82bbb 100644 --- a/htdocs/config.sample.php +++ b/htdocs/config.sample.php @@ -3,12 +3,12 @@ /** * 資料庫類型 */ - define('DB_TYPE', "mysql"); // or mysql + define('DB_TYPE', 'mysql'); // or mysql /** * 資料庫位址 */ - define('DB_HOST', "localhost"); + define('DB_HOST', 'localhost'); /** * 資料庫連結埠 @@ -20,24 +20,24 @@ /** * 資料庫連結帳號 */ - define('DB_USER', "user"); + define('DB_USER', 'user'); /** * 資料庫連結密碼 */ - define('DB_PASS', "passwd123"); + define('DB_PASS', 'passwd123'); /** * 資料庫名稱 */ - define('DB_NAME', "chu_elearning"); + define('DB_NAME', 'UElearning'); /** * 資料庫內資料表前綴字串 - * + * 每一張表格名稱的起始字串,為了避開一些網頁空間只允許建立一個資料庫的限制。 */ - define('DB_PREFIX', "chu_"); + define('DB_PREFIX', 'uel__'); // 網站設定 =================================================================== /** @@ -91,15 +91,14 @@ /** * 網站根目錄 */ - define('UELEARNING_ROOT', __DIR__.'/'); + define('UELEARNING_ROOT', __DIR__); /** * 內部函式庫根目錄 */ - define('UELEARNING_LIB_ROOT', UELEARNING_ROOT.'lib/'); + define('UELEARNING_LIB_ROOT', __DIR__.'/lib'); /** * 這份設定檔的路徑 */ define('UELEARNING_CONFIG_PATH', __FILE__); - diff --git a/htdocs/lib/Database/DBAdmin.php b/htdocs/lib/Database/DBAdmin.php index 1f7de8c..ca5bf50 100644 --- a/htdocs/lib/Database/DBAdmin.php +++ b/htdocs/lib/Database/DBAdmin.php @@ -7,8 +7,8 @@ namespace UElearning\Database; -require_once UELEARNING_LIB_ROOT.'Database/Database.php'; -require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Database.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; /** * 資料庫整體管理 diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index 9c1def8..1cfa80a 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -7,8 +7,8 @@ namespace UElearning\Database; -require_once UELEARNING_LIB_ROOT.'Database/Database.php'; -require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Database.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; /** * 使用者帳號資料表 diff --git a/htdocs/lib/Database/Database.php b/htdocs/lib/Database/Database.php index 6eff00c..f1bb2c7 100644 --- a/htdocs/lib/Database/Database.php +++ b/htdocs/lib/Database/Database.php @@ -8,8 +8,8 @@ namespace UElearning\Database; -require_once UELEARNING_LIB_ROOT.'Database/MySQLDB.php'; -require_once UELEARNING_LIB_ROOT.'Database/Exceptions.php'; +require_once UELEARNING_LIB_ROOT.'/Database/MySQLDB.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; use UElearning\Database\Exception; /** diff --git a/tests/InstallTest.php b/tests/InstallTest.php index 383899d..e0baafa 100644 --- a/tests/InstallTest.php +++ b/tests/InstallTest.php @@ -8,7 +8,7 @@ namespace UElearning; require_once __DIR__.'/../htdocs/config.php'; -require_once UELEARNING_LIB_ROOT.'Database/DBAdmin.php'; +require_once UELEARNING_LIB_ROOT.'/Database/DBAdmin.php'; class InstallTest extends \PHPUnit_Framework_TestCase { From 0bf3c54a276547e7fdcebf1cf627f0ee6d1e9f45 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sun, 17 Aug 2014 02:17:54 -0700 Subject: [PATCH 16/35] PHPUnit --- .gitignore | 3 +++ Gemfile | 9 +++++++++ Guardfile | 21 +++++++++++++++------ phpunit.xml | 9 +++++++++ tests/Database/DatabaseTest.php | 31 +++++++++++++++++++++++++++++++ tests/InstallTest.php | 1 - 6 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 Gemfile create mode 100644 phpunit.xml create mode 100644 tests/Database/DatabaseTest.php diff --git a/.gitignore b/.gitignore index 2d772a7..0008b19 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ vendor/ # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file composer.lock + +# Gem +Gemfile.lock diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..bf89039 --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +group :development do + gem 'guard' + gem 'guard-livereload', require: false + gem 'guard-shell' + gem 'guard-phpunit2' + gem 'rb-fsevent' + gem 'ruby_gntp' + gem 'growl' +end \ No newline at end of file diff --git a/Guardfile b/Guardfile index cee967f..9f83330 100644 --- a/Guardfile +++ b/Guardfile @@ -1,15 +1,15 @@ # A sample Guardfile # More info at https://github.com/guard/guard#readme -group :development do - gem 'guard' - gem 'guard-livereload', require: false - gem 'guard-shell' -end - # Add files and commands to this file, like the example: # watch(%r{file/path}) { `command(s)` } # + +# Mac用的通知中心 +notification :growl +# Linux用的通知中心 +notification :libnotify + guard :shell do watch(%r{htdocs/.+\.(php)}) do system 'phpdoc', '-d', './htdocs/lib', '-t', './docs/' @@ -20,3 +20,12 @@ end guard 'livereload' do watch(%r{htdocs/.+\.(php|css|js|html)}) end + +# PHPUnit +guard :phpunit2, :all_on_start => false, :tests_path => 'tests/', :cli => '--colors -c phpunit.xml' do + # Run any test in app/tests upon save. + watch(%r{^tests/.+Test\.php$}) + + # When a file is edited, try to run its associated test. + watch(%r{^htdocs/lib/(.+)\.php}) { |m| "tests/#{m[1]}Test.php" } +end \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..4091f0b --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,9 @@ + + + + + tests + + + \ No newline at end of file diff --git a/tests/Database/DatabaseTest.php b/tests/Database/DatabaseTest.php new file mode 100644 index 0000000..11e54b1 --- /dev/null +++ b/tests/Database/DatabaseTest.php @@ -0,0 +1,31 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/Database/DBAdmin.php'; + +class InstallTest extends \PHPUnit_Framework_TestCase +{ + + /** + * 測試安裝初始化資料庫 + */ + public function testInstallDatabase() + { + + try { + // 建立資料庫管理物件 + $dbAdmin = new Database\DBAdmin(); + + } + // 若設定的DBMS不被支援 則丟出例外 + catch (Database\Exception\DatabaseNoSupportException $e) { + throw $e; + } + } +} \ No newline at end of file diff --git a/tests/InstallTest.php b/tests/InstallTest.php index e0baafa..f0aff88 100644 --- a/tests/InstallTest.php +++ b/tests/InstallTest.php @@ -7,7 +7,6 @@ */ namespace UElearning; -require_once __DIR__.'/../htdocs/config.php'; require_once UELEARNING_LIB_ROOT.'/Database/DBAdmin.php'; class InstallTest extends \PHPUnit_Framework_TestCase From 082dd5534f578b43ecf7c06555daadc18699b2bb Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sun, 17 Aug 2014 12:29:20 -0700 Subject: [PATCH 17/35] rename UserControl -> UserAdmin & create user param array format --- htdocs/lib/User/UserAdmin.php | 51 +++++++++++++++++++++++++++++++++ htdocs/lib/User/UserControl.php | 37 ------------------------ tests/User/UserAdminTest.php | 0 3 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 htdocs/lib/User/UserAdmin.php delete mode 100644 htdocs/lib/User/UserControl.php create mode 100644 tests/User/UserAdminTest.php diff --git a/htdocs/lib/User/UserAdmin.php b/htdocs/lib/User/UserAdmin.php new file mode 100644 index 0000000..ae63d97 --- /dev/null +++ b/htdocs/lib/User/UserAdmin.php @@ -0,0 +1,51 @@ + + * @version 2.0.0 + * @package UElearning + * @subpackage User + */ +class UserAdmin { + + /** + * 建立使用者 + * + * @param array $userInfoArray 使用者資訊陣列,格式為: + * array( 'userId' => 'root', + * 'password' => 'pass123', + * 'password_encrypt' => null, // (optional) 預設為null + * 'groupId' => 'user', + * 'classId' => '5-2', // (optional) + * 'enable' => true, // (optional) 預設為true + * 'learnStyle_mode' => 'harf-line-learn', // (optional) + * 'material_mode' => 1, // (optional) + * 'nickname' => 'eric', // (optional) + * 'realname' => 'Eric Chiu', // (optional) + * 'email' => 'eric@example.tw', // (optional) + * 'memo' => '' ) // (optional) + * @since 2.0.0 + */ + public function create($userInfoArray) { + // TODO: Fill code in + } + + /** + * 是否已有相同名稱的帳號名稱 + * + * @param string $userName 帳號名稱 + * @return bool 已有相同的帳號名稱 + * @since 2.0.0 + */ + public function isExist($userName) { + // TODO: Fill code in + } + +} \ No newline at end of file diff --git a/htdocs/lib/User/UserControl.php b/htdocs/lib/User/UserControl.php deleted file mode 100644 index 0a07de5..0000000 --- a/htdocs/lib/User/UserControl.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @version 2.0.0 - * @package UElearning - * @subpackage User - */ -class UserControl { - - /** - * 建立使用者 - * @since 2.0.0 - */ - public function create() { - // TODO: Fill code in - } - - /** - * 是否已有相同名稱的帳號名稱 - * - * @param string $userName 帳號名稱 - * @return bool 已有相同的帳號名稱 - * @since 2.0.0 - */ - public function isExist($userName) { - // TODO: Fill code in - } - -} \ No newline at end of file diff --git a/tests/User/UserAdminTest.php b/tests/User/UserAdminTest.php new file mode 100644 index 0000000..e69de29 From 2ad3627c881ab00ee55fab85ece173e4a620701e Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 18 Aug 2014 02:34:25 -0700 Subject: [PATCH 18/35] class: DBUser & phpunit --- htdocs/lib/Database/DBUser.php | 61 ++++++++++++++++++++++++++++++++ phpunit.xml | 1 + tests/Database/DBUserTest.php | 61 ++++++++++++++++++++++++++++++++ tests/InstallTest.php | 64 +++++++++++++++++----------------- tests/User/UserAdminTest.php | 33 ++++++++++++++++++ 5 files changed, 188 insertions(+), 32 deletions(-) create mode 100644 tests/Database/DBUserTest.php diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index 1cfa80a..afec946 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -23,5 +23,66 @@ require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; */ class DBUser extends Database { + const FORM_USER = 'User'; + + /** + * 新增一個使用者 + * @param string $uId 使用者名稱 + * @param string $password 密碼 + * @param string $gId 群組 + * @param string $cId 班級 + * @param string $enable 啟用此帳號 + * @param string $l_mode 學習模式 + * @param string $m_mode 教材模式 + * @param string $nickName 暱稱 + * @param string $realName 姓名 + * @param string $email 電子郵件地址 + * @param string $memo 備註 + */ + public function insertUser($uId, $password, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo){ + + // 檢查是否有支援所設定的DBMS + if($this->db_type == 'mysql') { + + //紀錄使用者帳號進資料庫 + $sqlString = "INSERT INTO ".$this->table(self::FORM_USER). "(`UID`, `UPassword`, `GID`, `CID`, `UEnabled`, `UBuild_Time`, `LMode`, `MMode`, `UNickname`, `UReal_Name`, `UEmail`, `UMemo`) VALUES ( :id , :passwd, :gid , :cid , :enable , NOW() , :lmode , :mmode , :nickname , :realname , :email , :memo )"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":id", $uId); + $query->bindParam(":passwd", $uPassword); + $query->bindParam(":gid", $gId); + $query->bindParam(":cid", $cId); + $query->bindParam(":enable", $enable); + $query->bindParam(":lmode", $l_mode); + $query->bindParam(":mmode", $m_mode); + $query->bindParam(":nickname", $nickName); + $query->bindParam(":realname", $realName); + $query->bindParam(":email", $email); + $query->bindParam(":memo", $memo); + $query->execute(); + } + else { + throw new Exception\DatabaseNoSupportException($this->db_type); + } + + } + + /** + * 移除一位使用者 + * @param string $uId 使用者名稱 + */ + public function deleteUser($uId) { + if($this->db_type == 'mysql') { + $sqlString = "DELETE FROM ".$this->table(self::FORM_USER). " WHERE `UID` = :id "; + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":id", $uId); + $query->execute(); + } + else { + throw new Exception\DatabaseNoSupportException($this->db_type); + } + } } \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index 4091f0b..c6cda52 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -4,6 +4,7 @@ tests + tests/InstallTest.php \ No newline at end of file diff --git a/tests/Database/DBUserTest.php b/tests/Database/DBUserTest.php new file mode 100644 index 0000000..de9a4ec --- /dev/null +++ b/tests/Database/DBUserTest.php @@ -0,0 +1,61 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; +use UElearning\Database\DBUser; +use UElearning\Database\Exception; + +class DBUserTest extends \PHPUnit_Framework_TestCase +{ + + protected $db; + + protected function setUp(){ + try { + // 建立資料庫管理物件 + $this->db = new DBUser(); + + } + // 若設定的DBMS不被支援 則丟出例外 + catch (Database\Exception\DatabaseNoSupportException $e) { + throw $e; + } + } + + /** + * 測試建立使用者 + * + * @dataProvider userDataProvider + */ + public function testCreateUser($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo){ + + $this->db->insertUser($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo); + + } + + /** + * 測試移除使用者 + * + * @dataProvider userDataProvider + */ + public function testDeleteUser($uId) { + $this->db->deleteUser($uId); + } + + public function userDataProvider(){ + return array( + array('yuan', 'pass123', 'admin', null, true, 'harf-line-learn', 1, '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null) + ); + } +} \ No newline at end of file diff --git a/tests/InstallTest.php b/tests/InstallTest.php index f0aff88..872d64c 100644 --- a/tests/InstallTest.php +++ b/tests/InstallTest.php @@ -1,33 +1,33 @@ - */ -namespace UElearning; - -require_once UELEARNING_LIB_ROOT.'/Database/DBAdmin.php'; - -class InstallTest extends \PHPUnit_Framework_TestCase -{ - - /** - * 測試安裝初始化資料庫 - */ - public function testInstallDatabase() - { - - try { - // 建立資料庫管理物件 - $dbAdmin = new Database\DBAdmin(); - - // 建立所有所需的資料表 - $dbAdmin->createAllTable(); - } - // 若設定的DBMS不被支援 則丟出例外 - catch (Database\Exception\DatabaseNoSupportException $e) { - throw $e; - } - } -} \ No newline at end of file +///** +// * InstallTest +// * +// * @package UElearning +// * @author Yuan Chiu +// */ +//namespace UElearning; +// +//require_once UELEARNING_LIB_ROOT.'/Database/DBAdmin.php'; +// +//class InstallTest extends \PHPUnit_Framework_TestCase +//{ +// +// /** +// * 測試安裝初始化資料庫 +// */ +// public function testInstallDatabase() +// { +// +// try { +// // 建立資料庫管理物件 +// $dbAdmin = new Database\DBAdmin(); +// +// // 建立所有所需的資料表 +// $dbAdmin->createAllTable(); +// } +// // 若設定的DBMS不被支援 則丟出例外 +// catch (Database\Exception\DatabaseNoSupportException $e) { +// throw $e; +// } +// } +//} \ No newline at end of file diff --git a/tests/User/UserAdminTest.php b/tests/User/UserAdminTest.php index e69de29..1beed5a 100644 --- a/tests/User/UserAdminTest.php +++ b/tests/User/UserAdminTest.php @@ -0,0 +1,33 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/User/UserAdmin.php'; +use UElearning\User\UserAdmin; + +class UserAdminTest extends \PHPUnit_Framework_TestCase +{ + + /** + * 測試安裝初始化資料庫 + */ + public function testCreateUser() + { + + try { + // 建立資料庫管理物件 + $dbAdmin = new UserAdmin(); + + // TODO: 建立使用者 + } + // 若設定的DBMS不被支援 則丟出例外 + catch (Database\Exception\DatabaseNoSupportException $e) { + throw $e; + } + } +} \ No newline at end of file From 5d92668456208906b5ad06cbe9086ec48baa1327 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Thu, 21 Aug 2014 13:46:14 +0800 Subject: [PATCH 19/35] =?UTF-8?q?fix=20DBUser:=20=E5=B8=B6=E5=85=A5?= =?UTF-8?q?=E7=9A=84=E8=AE=8A=E6=95=B8=E5=90=8D=E7=A8=B1=E5=92=8C=E5=AF=A6?= =?UTF-8?q?=E9=9A=9B=E6=B5=81=E7=A8=8B=E7=9A=84=E8=AE=8A=E6=95=B8=E5=90=8D?= =?UTF-8?q?=E7=A8=B1=E6=B2=92=E5=B0=8D=E5=88=B0=20->?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/lib/Database/DBUser.php | 22 +++++++++++++++++++++- tests/Database/DBUserTest.php | 7 +++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index afec946..fb6e693 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -51,7 +51,7 @@ class DBUser extends Database { $query = $this->connDB->prepare($sqlString); $query->bindParam(":id", $uId); - $query->bindParam(":passwd", $uPassword); + $query->bindParam(":passwd", $password); $query->bindParam(":gid", $gId); $query->bindParam(":cid", $cId); $query->bindParam(":enable", $enable); @@ -69,6 +69,26 @@ class DBUser extends Database { } + /** + * 查詢一位使用者帳號資料 + * @param string $uId 使用者名稱 + * @return array 使用者資料 (TODO 格式待補) + */ + public function queryUser($uId) { + + $sqlString = "SELECT * FROM ".$db->table('User')." WHERE `UID` = :uid"; + + $query = $this->prepare($sqlString); + $query->bindParam(':uid',$this->thisUID); + $query->execute(); + + $result = $query->fetchAll(); + $this->infoArray = $result; + return $this->infoArray; + + // TODO unTested + } + /** * 移除一位使用者 * @param string $uId 使用者名稱 diff --git a/tests/Database/DBUserTest.php b/tests/Database/DBUserTest.php index de9a4ec..9b6ef1b 100644 --- a/tests/Database/DBUserTest.php +++ b/tests/Database/DBUserTest.php @@ -41,7 +41,6 @@ class DBUserTest extends \PHPUnit_Framework_TestCase $this->db->insertUser($uId, $uPassword, $gId, $cId, $enable, $l_mode, $m_mode, $nickName, $realName, $email, $memo); - } /** @@ -53,9 +52,13 @@ class DBUserTest extends \PHPUnit_Framework_TestCase $this->db->deleteUser($uId); } + /** + * 測試時要填的資料 + */ public function userDataProvider(){ return array( - array('yuan', 'pass123', 'admin', null, true, 'harf-line-learn', 1, '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null) + array('yuan_unittest', 'pass123', 'admin', null, true, 'harf-line-learn', 1, '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null), + array('eee_unittest', 'qqqssss', 'admin', null, 1, 'harf-line-learn', '1', 'sss', 'Yuan Chiu', 'chyuanesr@gmail.com', null) ); } } \ No newline at end of file From 7785baa7931592ccf7989431be30f763cac7ec6d Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Tue, 2 Sep 2014 23:51:13 +0800 Subject: [PATCH 20/35] =?UTF-8?q?UserAdmin=E6=89=80=E6=9C=89=E7=9B=B8?= =?UTF-8?q?=E9=97=9C=E7=9A=84=E5=85=A7=E9=83=A8=E5=87=BD=E5=BC=8F=E5=BA=AB?= =?UTF-8?q?=20(=E5=90=AB=E8=B3=87=E6=96=99=E5=BA=AB=E4=BF=AE=E5=BE=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Config/{Exceptions.php => Exception.php} | 0 htdocs/lib/Database/DBAdmin.php | 2 +- htdocs/lib/Database/DBUser.php | 49 +++++-- htdocs/lib/Database/Database.php | 2 +- .../{Exceptions.php => Exception.php} | 0 htdocs/lib/Exception.php | 52 ++++++++ .../User/{Exceptions.php => Exception.php} | 8 +- htdocs/lib/User/UserAdmin.php | 126 ++++++++++++++++-- tests/Database/DBUserTest.php | 37 ++++- tests/User/UserAdminTest.php | 71 +++++++++- 10 files changed, 311 insertions(+), 36 deletions(-) rename htdocs/lib/Config/{Exceptions.php => Exception.php} (100%) rename htdocs/lib/Database/{Exceptions.php => Exception.php} (100%) create mode 100644 htdocs/lib/Exception.php rename htdocs/lib/User/{Exceptions.php => Exception.php} (86%) diff --git a/htdocs/lib/Config/Exceptions.php b/htdocs/lib/Config/Exception.php similarity index 100% rename from htdocs/lib/Config/Exceptions.php rename to htdocs/lib/Config/Exception.php diff --git a/htdocs/lib/Database/DBAdmin.php b/htdocs/lib/Database/DBAdmin.php index ca5bf50..a010c3a 100644 --- a/htdocs/lib/Database/DBAdmin.php +++ b/htdocs/lib/Database/DBAdmin.php @@ -8,7 +8,7 @@ namespace UElearning\Database; require_once UELEARNING_LIB_ROOT.'/Database/Database.php'; -require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exception.php'; /** * 資料庫整體管理 diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index fb6e693..0db933a 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -8,7 +8,7 @@ namespace UElearning\Database; require_once UELEARNING_LIB_ROOT.'/Database/Database.php'; -require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exception.php'; /** * 使用者帳號資料表 @@ -47,7 +47,11 @@ class DBUser extends Database { if($this->db_type == 'mysql') { //紀錄使用者帳號進資料庫 - $sqlString = "INSERT INTO ".$this->table(self::FORM_USER). "(`UID`, `UPassword`, `GID`, `CID`, `UEnabled`, `UBuild_Time`, `LMode`, `MMode`, `UNickname`, `UReal_Name`, `UEmail`, `UMemo`) VALUES ( :id , :passwd, :gid , :cid , :enable , NOW() , :lmode , :mmode , :nickname , :realname , :email , :memo )"; + $sqlString = "INSERT INTO ".$this->table('User'). + " (`UID`, `UPassword`, `GID`, `CID`, `UEnabled`, `UBuild_Time`, + `LMode`, `MMode`, `UNickname`, `UReal_Name`, `UEmail`, `UMemo`) + VALUES ( :id , :passwd, :gid , :cid , :enable , NOW() , + :lmode , :mmode , :nickname , :realname , :email , :memo )"; $query = $this->connDB->prepare($sqlString); $query->bindParam(":id", $uId); @@ -76,17 +80,37 @@ class DBUser extends Database { */ public function queryUser($uId) { - $sqlString = "SELECT * FROM ".$db->table('User')." WHERE `UID` = :uid"; + $sqlString = "SELECT * FROM ".$this->table('User'). + " WHERE `UID` = :uid"; - $query = $this->prepare($sqlString); - $query->bindParam(':uid',$this->thisUID); + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':uid', $uId); $query->execute(); - $result = $query->fetchAll(); - $this->infoArray = $result; - return $this->infoArray; - - // TODO unTested + $queryResultAll = $query->fetchAll(); + if( count($queryResultAll) >= 1 ) { + $queryResult = $queryResultAll[0]; + + $result = array( + 'user_id' => $queryResult['UID'], + 'password' => $queryResult['UPassword'], + 'group_id' => $queryResult['GID'], + 'class_id' => $queryResult['CID'], + 'enable' => $queryResult['UEnabled'], + 'build_time' => $queryResult['UBuild_Time'], + 'learnStyle_mode' => $queryResult['LMode'], + 'material_mode' => $queryResult['MMode'], + 'nickname' => $queryResult['UNickname'], + 'realname' => $queryResult['UReal_Name'], + 'email' => $queryResult['UEmail'], + 'memo' => $queryResult['UMemo'] + ); + + return $result; + } + else { + return null; + } } /** @@ -94,8 +118,11 @@ class DBUser extends Database { * @param string $uId 使用者名稱 */ public function deleteUser($uId) { + if($this->db_type == 'mysql') { - $sqlString = "DELETE FROM ".$this->table(self::FORM_USER). " WHERE `UID` = :id "; + $sqlString = "DELETE FROM ".$this->table(self::FORM_USER). + " WHERE `UID` = :id "; + $query = $this->connDB->prepare($sqlString); $query->bindParam(":id", $uId); $query->execute(); diff --git a/htdocs/lib/Database/Database.php b/htdocs/lib/Database/Database.php index f1bb2c7..ac5de92 100644 --- a/htdocs/lib/Database/Database.php +++ b/htdocs/lib/Database/Database.php @@ -9,7 +9,7 @@ namespace UElearning\Database; require_once UELEARNING_LIB_ROOT.'/Database/MySQLDB.php'; -require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exception.php'; use UElearning\Database\Exception; /** diff --git a/htdocs/lib/Database/Exceptions.php b/htdocs/lib/Database/Exception.php similarity index 100% rename from htdocs/lib/Database/Exceptions.php rename to htdocs/lib/Database/Exception.php diff --git a/htdocs/lib/Exception.php b/htdocs/lib/Exception.php new file mode 100644 index 0000000..aace491 --- /dev/null +++ b/htdocs/lib/Exception.php @@ -0,0 +1,52 @@ +fieldName = $fieldName; + parent::__construct(); + } + else { + $this->fieldName = array(); + } + } + + /** + * 新增一項未輸入的欄位名稱 + */ + public function addFieldName($fieldName) { + $this->fieldName += array($fieldName); + } + + /** + * 取得未輸入的欄位名稱 + * @return string|array 欄位名稱 + */ + public function getFieldName() { + return $this->fieldName; + } +} diff --git a/htdocs/lib/User/Exceptions.php b/htdocs/lib/User/Exception.php similarity index 86% rename from htdocs/lib/User/Exceptions.php rename to htdocs/lib/User/Exception.php index 7cd1119..2d9b44e 100644 --- a/htdocs/lib/User/Exceptions.php +++ b/htdocs/lib/User/Exception.php @@ -49,7 +49,7 @@ class UserNoFoundException extends UserException { * @param string $userId 輸入的使用者名稱 */ public function __construct($userId) { - parent::__construct($userId, 'User: "'.$this->type.'" is no found.'); + parent::__construct($userId, 'User: "'.$userId.'" is no found.'); } } @@ -63,7 +63,7 @@ class UserPasswordErrException extends UserException { * @param string $userId 輸入的使用者名稱 */ public function __construct($userId) { - parent::__construct($userId, 'User: "'.$this->type.'" password is wrong.'); + parent::__construct($userId, 'User: "'.$userId.'" password is wrong.'); } } @@ -77,7 +77,7 @@ class UserNoActivatedException extends UserException { * @param string $userId 輸入的使用者名稱 */ public function __construct($userId) { - parent::__construct($userId, 'User: "'.$this->type.'" is no activated.'); + parent::__construct($userId, 'User: "'.$userId.'" is no activated.'); } } @@ -92,6 +92,6 @@ class UserIdExistException extends UserException { * @param string $userId 輸入的使用者名稱 */ public function __construct($userId) { - parent::__construct($userId, 'UserId: "'.$this->type.'" is exist.'); + parent::__construct($userId, 'UserId: "'.$userId.'" is exist.'); } } diff --git a/htdocs/lib/User/UserAdmin.php b/htdocs/lib/User/UserAdmin.php index ae63d97..db887a1 100644 --- a/htdocs/lib/User/UserAdmin.php +++ b/htdocs/lib/User/UserAdmin.php @@ -5,6 +5,11 @@ namespace UElearning\User; +require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; +require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Exception.php'; +use UElearning\Database; + /** * 管理使用者的操作 * @@ -18,23 +23,111 @@ class UserAdmin { /** * 建立使用者 * + * 建立使用者範例: + * + * try { + * $userAdmin = new User\UserAdmin(); + * $userAdmin->create( + * array( 'user_id' => 'eric', + * 'password' => 'pass123', + * 'group_id' => 'admin', + * 'enable' => true, + * 'nickname' => '艾瑞克', + * 'email' => 'eric@example.com' + * )); + * + * } + * // 若已有重複帳號名稱 + * catch (User\Exception\UserIdExistException $e) { + * echo 'Is exist user: ', $e->getUserId(); + * } + * * @param array $userInfoArray 使用者資訊陣列,格式為: - * array( 'userId' => 'root', - * 'password' => 'pass123', - * 'password_encrypt' => null, // (optional) 預設為null - * 'groupId' => 'user', - * 'classId' => '5-2', // (optional) - * 'enable' => true, // (optional) 預設為true - * 'learnStyle_mode' => 'harf-line-learn', // (optional) - * 'material_mode' => 1, // (optional) - * 'nickname' => 'eric', // (optional) - * 'realname' => 'Eric Chiu', // (optional) - * 'email' => 'eric@example.tw', // (optional) - * 'memo' => '' ) // (optional) + * array( 'user_id' => 'root', + * 'password' => 'pass123', + * 'password_encrypt' => null, // (optional) 預設為null + * 'password_encrypted' => null, // (optional) 預設為false + * 'group_id' => 'user', + * 'class_id' => '5-2', // (optional) + * 'enable' => true, // (optional) 預設為true + * 'learnStyle_mode' => 'harf-line-learn', // (optional) + * 'material_mode' => 1, // (optional) + * 'nickname' => 'eric', // (optional) + * 'realname' => 'Eric Chiu', // (optional) + * 'email' => 'eric@example.tw', // (optional) + * 'memo' => '' ) // (optional) * @since 2.0.0 */ public function create($userInfoArray) { - // TODO: Fill code in + + // 檢查必填項目有無填寫 + if(isset($userInfoArray)) { + + // 若無填寫 + if( !isset($userInfoArray['user_id']) || + !isset($userInfoArray['password']) || + !isset($userInfoArray['group_id']) ) { + throw new UElearning\Exception\NoDataException(); + } + // 若此id已存在 + else if($this->isExist($userInfoArray['user_id'])) { + throw new Exception\UserIdExistException( + $userInfoArray['user_id'] ); + } + // 沒有問題 + else { + + // 處理未帶入的資料 + if( !isset($userInfoArray['class_id']) ){ + $userInfoArray['class_id'] = null; + } + if( !isset($userInfoArray['enable']) ){ + $userInfoArray['enable'] = true; + } + if( !isset($userInfoArray['learnStyle_mode']) ){ + $userInfoArray['learnStyle_mode'] = null; + } + if( !isset($userInfoArray['material_mode']) ){ + $userInfoArray['material_mode'] = null; + } + if( !isset($userInfoArray['nickname']) ){ + $userInfoArray['nickname'] = null; + } + if( !isset($userInfoArray['realname']) ){ + $userInfoArray['realname'] = null; + } + if( !isset($userInfoArray['email']) ){ + $userInfoArray['email'] = null; + } + if( !isset($userInfoArray['memo']) ){ + $userInfoArray['memo'] = null; + } + + // 進行密碼加密 + /*if( isset($userInfoArray['userId']) ) { + // TODO: 密碼加密 + }*/ + // 加密後的密碼 + $passwdEncrypted = $userInfoArray['password']; + + // 新增一筆使用者資料進資料庫 + $db = new Database\DBUser(); + $db->insertUser( + $userInfoArray['user_id'], + $passwdEncrypted, + $userInfoArray['group_id'], + $userInfoArray['class_id'], + $userInfoArray['enable'], + $userInfoArray['learnStyle_mode'], + $userInfoArray['material_mode'], + $userInfoArray['nickname'], + $userInfoArray['realname'], + $userInfoArray['email'], + $userInfoArray['memo'] + ); + } + } + else throw Exception\NoDataException(); } /** @@ -45,7 +138,12 @@ class UserAdmin { * @since 2.0.0 */ public function isExist($userName) { - // TODO: Fill code in + + $db = new Database\DBUser(); + $info = $db->queryUser($userName); + + if( $info != null ) return true; + else return false; } } \ No newline at end of file diff --git a/tests/Database/DBUserTest.php b/tests/Database/DBUserTest.php index 9b6ef1b..86a89ac 100644 --- a/tests/Database/DBUserTest.php +++ b/tests/Database/DBUserTest.php @@ -8,7 +8,7 @@ namespace UElearning; require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; -require_once UELEARNING_LIB_ROOT.'/Database/Exceptions.php'; +require_once UELEARNING_LIB_ROOT.'/Database/Exception.php'; use UElearning\Database\DBUser; use UElearning\Database\Exception; @@ -43,6 +43,32 @@ class DBUserTest extends \PHPUnit_Framework_TestCase $nickName, $realName, $email, $memo); } + /** + * 測試查詢使用者 + * + * @dataProvider userDataProvider + */ + public function testQueryUser($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo){ + + // 查詢使用者 + $info = $this->db->queryUser($uId); + + // 比對資料是否吻合 + $this->assertEquals($info['user_id'], $uId); + $this->assertEquals($info['password'], $uPassword); + $this->assertEquals($info['group_id'], $gId); + $this->assertEquals($info['class_id'], $cId); + $this->assertEquals($info['enable'], $enable); + $this->assertEquals($info['learnStyle_mode'], $l_mode); + $this->assertEquals($info['material_mode'], $m_mode); + $this->assertEquals($info['nickname'], $nickName); + $this->assertEquals($info['realname'], $realName); + $this->assertEquals($info['email'], $email); + $this->assertEquals($info['memo'], $memo); + } + /** * 測試移除使用者 * @@ -57,8 +83,13 @@ class DBUserTest extends \PHPUnit_Framework_TestCase */ public function userDataProvider(){ return array( - array('yuan_unittest', 'pass123', 'admin', null, true, 'harf-line-learn', 1, '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null), - array('eee_unittest', 'qqqssss', 'admin', null, 1, 'harf-line-learn', '1', 'sss', 'Yuan Chiu', 'chyuanesr@gmail.com', null) + array('yuan_unittest', 'pass123', 'admin', null, true, + 'harf-line-learn', 1, + '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null), + + array('eee_unittest', 'qqqssss', 'admin', null, 1, + 'harf-line-learn', '1', + 'sss', 'Yuan Chiu', 'chyuanesr@gmail.com', null) ); } } \ No newline at end of file diff --git a/tests/User/UserAdminTest.php b/tests/User/UserAdminTest.php index 1beed5a..873c4ee 100644 --- a/tests/User/UserAdminTest.php +++ b/tests/User/UserAdminTest.php @@ -15,19 +15,86 @@ class UserAdminTest extends \PHPUnit_Framework_TestCase /** * 測試安裝初始化資料庫 + * + * @dataProvider userDataProvider */ - public function testCreateUser() + public function testCreateUser($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo) { try { // 建立資料庫管理物件 - $dbAdmin = new UserAdmin(); + $userAdmin = new UserAdmin(); // TODO: 建立使用者 + $userAdmin->create( + array( 'user_id' => $uId, + 'password' => $uPassword, + //'password_encrypt' => null, + //'password_encrypted' => null, + 'group_id' => $gId, + 'class_id' => $cId, + 'enable' => $enable, + 'learnStyle_mode' => $l_mode, + 'material_mode' => $m_mode, + 'nickname' => $nickName, + 'realname' => $realName, + 'email' => $email, + 'memo' => $memo + )); } // 若設定的DBMS不被支援 則丟出例外 catch (Database\Exception\DatabaseNoSupportException $e) { throw $e; } } + + /** + * 檢查是否已確實建立 + * + * @dataProvider userDataProvider + */ + public function testCheckExist($uId) + { + // 建立資料庫管理物件 + $userAdmin = new UserAdmin(); + + // 檢查是否已確實建立 + $this->assertEquals($userAdmin->isExist($uId), true); + } + + /** + * 刪除建立的帳號(恢復原狀用) + * + * @dataProvider userDataProvider + */ + public function testDeleteUser($uId) + { + // TODO: 待UserAdmin的移除功能寫好後,請改用UserAdmin + require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; + + // 建立資料庫管理物件 + $db = new Database\DBUser(); + $db->deleteUser($uId); + + } + + + + /** + * 測試時要填的資料 + */ + public function userDataProvider(){ + return array( + array('yuan_unittest', 'pass123', 'admin', null, true, + 'harf-line-learn', 1, + '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null), + + array('eee_unittest', 'qqqssss', 'admin', null, 1, + 'harf-line-learn', '1', + 'sss', 'Yuan Chiu', 'chyuanesr@gmail.com', null) + ); + } + } \ No newline at end of file From b70dc95c6c1048abad077652720ece125d888692 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Fri, 19 Sep 2014 20:33:31 +0800 Subject: [PATCH 21/35] UserAdmin Class: remove --- htdocs/lib/User/UserAdmin.php | 26 ++++++++++++++++++++++++++ tests/User/UserAdminTest.php | 12 +++++++----- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/htdocs/lib/User/UserAdmin.php b/htdocs/lib/User/UserAdmin.php index db887a1..cff0cfa 100644 --- a/htdocs/lib/User/UserAdmin.php +++ b/htdocs/lib/User/UserAdmin.php @@ -56,6 +56,7 @@ class UserAdmin { * 'realname' => 'Eric Chiu', // (optional) * 'email' => 'eric@example.tw', // (optional) * 'memo' => '' ) // (optional) + * @throw UElearning\User\Exception\UserIdExistException * @since 2.0.0 */ public function create($userInfoArray) { @@ -145,5 +146,30 @@ class UserAdmin { if( $info != null ) return true; else return false; } + + /** + * 移除此使用者 + * + * @param string $userName 帳號名稱 + * @throw UElearning\User\Exception\UserNoFoundException + * @since 2.0.0 + */ + public function remove($userName) { + + // 若有此使用者 + if($this->isExist($userName)) { + + // TODO: 檢查所有關聯的資料,確認是否可以移除 + + // 移除資料庫中的使用者 + $db = new Database\DBUser(); + $db->deleteUser($userName); + } + // 若沒有這位使用者 + else { + throw new Exception\UserNoFoundException($userName); + } + + } } \ No newline at end of file diff --git a/tests/User/UserAdminTest.php b/tests/User/UserAdminTest.php index 873c4ee..b3c8212 100644 --- a/tests/User/UserAdminTest.php +++ b/tests/User/UserAdminTest.php @@ -71,12 +71,14 @@ class UserAdminTest extends \PHPUnit_Framework_TestCase */ public function testDeleteUser($uId) { - // TODO: 待UserAdmin的移除功能寫好後,請改用UserAdmin - require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; - // 建立資料庫管理物件 - $db = new Database\DBUser(); - $db->deleteUser($uId); + $userAdmin = new UserAdmin(); + + // 移除此使用者 + $userAdmin->remove($uId); + + // 檢查是否已確實建立 + $this->assertEquals($userAdmin->isExist($uId), false); } From e4d6cba1aee22f1dbee95f264d931e72321ba238 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 22 Sep 2014 20:22:22 +0800 Subject: [PATCH 22/35] Password Util Class --- htdocs/lib/Util/Password.php | 153 +++++++++++++++++++++++++++++++++++ tests/Util/PasswordTest.php | 63 +++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 htdocs/lib/Util/Password.php create mode 100644 tests/Util/PasswordTest.php diff --git a/htdocs/lib/Util/Password.php b/htdocs/lib/Util/Password.php new file mode 100644 index 0000000..2bd5b45 --- /dev/null +++ b/htdocs/lib/Util/Password.php @@ -0,0 +1,153 @@ + + * @version 2.0.0 + * @package UElearning + * @subpackage Util + */ +class Password { + + /** + * 取得亂數字串 + * + * The MIT License + * + * Copyright (c) 2007 Tsung-Hao + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author tsung http://plog.longwin.com.tw + * @desc http://blog.longwin.com.tw/2007/11/php_snap_image_block_2007/ + * @param int $password_len 字串長度(幾個字) + * @return string 亂數產生產生後的字串 + * + */ + public function generator($password_len) + { + $password = ''; + + // remove o,0,1,l + $word = 'abcdefghijkmnpqrstuvwxyz!@#%^*()-ABCDEFGHIJKLMNPQRSTUVWXYZ;{}[]23456789'; + $len = strlen($word); + + for ($i = 0; $i < $password_len; $i++) { + $password .= $word[rand() % $len]; + } + + return $password; + } + + /** + * 加密這段字 + * + * @param string $text 原本字串 + * @return string 加密後結果字串 + * @since 2.0.0 + */ + public function encrypt($text){ + // TODO: 尚未測試 + + // 從config.php設定檔取得預設加密方式 + switch(ENCRYPT_MODE){ + case "MD5": + case "md5": + return $this->md5Encrypt($text); + break; + case "SHA1": + case "sha1": + return $this->sha1Encrypt($text); + break; + case "CRYPT": + case "crypt": + return $this->cryptEncrypt($text); + break; + default: + return $text; + break; + } + } + + /** + * 加密這段字 + * + * @param string $encrypted 已加密字串 + * @param string $text 原本字串 + * @return bool true代表與加密後字串一樣 + * @since 2.0.0 + */ + public function checkSame($encrypted, $text) { + // TODO: 尚未測試 + + // 加密此字串 + $textToEncypt = $this->encrypt($text); + + // 判斷是否吻合 + if( $textToEncypt == $encrypted ) { + return true; + } + else { + return false; + } + } + + // ------------------------------------------------------------------------ + + /** + * MD5加密這段字 + * + * @param string $text 原本字串 + * @return string 加密後結果字串 + * @since 2.0.0 + */ + public function md5Encrypt($text){ + return md5($text); + } + + /** + * SHA1加密這段字 + * + * @param string $text 原本字串 + * @return string 加密後結果字串 + * @since 2.0.0 + */ + public function sha1Encrypt($text){ + return sha1($text); + } + + /** + * CRYPT加密這段字 + * + * @param string $text 原本字串 + * @return string 加密後結果字串 + * @since 2.0.0 + */ + public function cryptEncrypt($text){ + return crypt($text); + } + +} \ No newline at end of file diff --git a/tests/Util/PasswordTest.php b/tests/Util/PasswordTest.php new file mode 100644 index 0000000..8783c61 --- /dev/null +++ b/tests/Util/PasswordTest.php @@ -0,0 +1,63 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/Util/Password.php'; +use UElearning\Util\Password; + +class PasswordTest extends \PHPUnit_Framework_TestCase +{ + + protected $passUtil; + + public function setUp(){ + // 建立密碼函式物件 + $this->passUtil = new Password(); + } + + /** + * 檢查密碼與加密後是否一樣 + * + * @dataProvider pass_dataProvider + */ + public function testCheckSame($data){ + + // 加密字串 + $encode = $this->passUtil->encrypt($value); + // 比對和加密後是否吻合 + $this->assertEquals($this->passUtil->checkSame($encode, $value), true); + } + + + /** + * 測試時要填的資料 + */ + public function pass_dataProvider(){ + + // 隨機產生測試數據 + $num = 10; // 產生幾筆測試字串 + $passUtil = new Password(); + $data_array = array(); + + for($i=0; $i<$num; $i++) { + $generator_text = $passUtil->generator(50); + array_push($data_array, array( $generator_text )); + } + + + return $data_array; + + // 固定測試字串 + /*return array( + array('123'), + array('sa'), + array('asdfmlsdm'), + array('dsamvlkscml') + );*/ + } +} \ No newline at end of file From 6f6f08fd9b112914c0819d4256d7059927edc8b1 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 29 Sep 2014 23:20:41 +0800 Subject: [PATCH 23/35] add debug page --- htdocs/debug/project_info.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 htdocs/debug/project_info.php diff --git a/htdocs/debug/project_info.php b/htdocs/debug/project_info.php new file mode 100644 index 0000000..3f66fbf --- /dev/null +++ b/htdocs/debug/project_info.php @@ -0,0 +1,27 @@ + + + + + + + 專案設定資訊 + + +

    系統資訊

    +
      +
    • 主機名稱:
    • +
    + +

    專案設定資訊

    +
      +
    • 資料庫類型:
    • +
    • 資料庫位址:
    • +
    • 資料庫連結埠:
    • +
    • 資料庫連結帳號:
    • +
    • 資料庫名稱:
    • +
    • 資料庫內資料表前綴字串:
    • +
    + + \ No newline at end of file From 078cead34e16432f236dcc09e611739e3b766de5 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 29 Sep 2014 23:27:37 +0800 Subject: [PATCH 24/35] fix Gemfile & Guardfile --- Gemfile | 2 ++ Guardfile | 1 + 2 files changed, 3 insertions(+) diff --git a/Gemfile b/Gemfile index bf89039..2ec68f2 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,4 @@ +source 'https://rubygems.org' group :development do gem 'guard' gem 'guard-livereload', require: false @@ -6,4 +7,5 @@ group :development do gem 'rb-fsevent' gem 'ruby_gntp' gem 'growl' + gem 'libnotify' end \ No newline at end of file diff --git a/Guardfile b/Guardfile index 9f83330..bd862b6 100644 --- a/Guardfile +++ b/Guardfile @@ -10,6 +10,7 @@ notification :growl # Linux用的通知中心 notification :libnotify +#PHPDoc guard :shell do watch(%r{htdocs/.+\.(php)}) do system 'phpdoc', '-d', './htdocs/lib', '-t', './docs/' From 2888922baf3e20dc9697dc3e0fb8f000e87c8a2d Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Tue, 30 Sep 2014 18:32:31 +0800 Subject: [PATCH 25/35] Edit README Install Guide --- README.md | 151 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ffde88c..c696e26 100644 --- a/README.md +++ b/README.md @@ -7,46 +7,144 @@ ## 使用需求 * PHP5.3 以上,需要有以下Extension: - * pdo_mysql + * pdo-mysql * zip + * mcrypt * MariaDB 5.5.31 (可用MySQL) +## 建置伺服器環境 + +### 1. 安裝Apache + MySQL + +For Linux Debian, Ubuntu: + + # 更新套件庫、升級系統內套件 + sudo apt-get update; sudo apt-get upgrade -y + # 安裝Apache, MySQL, PHP(附帶需要的Extensions) + sudo apt-get install apache2 mysql-server php5 php5-mysql php5-mcrypt phpmyadmin -y + +### 2. 編輯Apache網站設定檔(vhost) + +1. 編輯以下文件: + * ArchLinux: `/etc/httpd/conf/extra/httpd-vhosts.conf` + * Ubuntu: `/etc/apache2/sites-available/uelearning.conf` + + 加入以下內容: + + + ServerName uelearning.yourdomain.name + ServerAdmin admin@yourdomain.name + + DocumentRoot /srv/http/website/E-learning-Server/htdocs + DirectoryIndex index.php index.shtml index.html + + + Options FollowSymLinks MultiViews + AllowOverride All + Allow from All + Order allow,deny + Require all granted #Apache 2.4以上版本需加此行,若在Apache2.2請移除此行 + + +2. 啟用本站/重新啟動伺服器: + * ArchLinux: `$ sudo systemctl restart httpd.service` + * Debian, Ubuntu: + 1. `$ sudo a2ensite uelearning` + 2. `$ service apache2 reload` + +### 3. 編輯Apache設定 +Linux Debian: `sudo a2enmod rewrite` + +非Debian or Ubuntu的,請開啟以下設定檔: + +* Windows: 到`C:\AppServ\Apache2.2\conf\httpd.conf` +* Arch Linux: 到`/etc/httpd/conf/httpd.conf` + +將 `LoadModule rewrite_module modules/mod_rewrite.so` 取消註解 + +### 4. 編輯PHP設定 + +開啟以下設定檔: + +* Windows: 到`C:\Windows\php.ini +* Arch Linux: 到`/etc/php/php.ini` + +找到`output_buffering`那行修改成 `output_buffering = On`。(`output_buffering = 4096`也OK) + +並將`extension=php_pdo.dll`和`extension=php_pdo_mysql.dll`取消註解。(Linux請把`.so`當成`.dll`看待) + +### 5. 啟用本站/重新啟動伺服器: + +* Windows: + 1. `C:\AppServ\Apache2.2\apache_serviceuninstall.bat` + 2. `C:\AppServ\Apache2.2\apache_serviceinstall.bat` +* ArchLinux: `$ sudo systemctl restart httpd.service` +* Ubuntu: `$ sudo service apache2 reload` + +## 安裝此系統 +請擇一選擇安裝方式: +### 引導式安裝 +**>>> 施工中,請勿使用 <<<** + +### 手動安裝 +1. 請先把 `/htdocs/` 整個複製到你的網頁空間 +2. 將內附的 `/sql/UElearning.sql` 匯入進你的資料庫 +3. 將 `/htdocs/config.sample.php` 檔案複製成 `config.php` ,並依你的需求修改。 + + *** ## 開發需求 * 支援UTF-8編碼的文字編輯器 * 開發文件產生器: phpdoc +* 單元測試: phpunit * 自動化建置工具 * guard(需有ruby環境) * guard-shell * guard-livereload + * guard-phpunit2 (不是guard-phpunit) ## 建置開發環境 -### 安裝php, ruby 環境 -TODO: 代補,需有`gem`, `phar` +### 安裝PHP套件管理程式-pear + sudo apt-get install php-pear -### 安裝Guard +### 安裝PHPDoc, PHPUnit +安裝PHPDoc: - gem install guard - gem install guard-shell - gem install guard-livereload + sudo pear channel-discover pear.phpdoc.org + sudo pear install phpdoc/phpDocumentor + +安裝PHPUnit: + + sudo pear channel-discover pear.phpunit.de + sudo pear install phpunit/PHPUnit + +### 安裝自動化工具 +安裝Guard所需套件 + + sudo apt-get install g++ gem wget + sudo gem install bundler -#### 瀏覽器plugin安裝 +安裝此專案所需的套件 + + cd E-learning-Server # 進入專案資料夾 + bundler install + bundle exec guard + +PS. 若出現`ArgumentError: invalid byte sequence in US-ASCII`錯誤,是因為Ruby<2.0 以下版本預設編碼是採用**US-ASCII**,必須下以下兩行指令來修正此問題: + + export LANG="C.UTF-8" + export LC_ALL="C.UTF-8" + +為了減少每次都要下此兩行的麻煩,建議可寫在`~/.bashrc`裡,自動指定編碼。 + +### 瀏覽器plugin安裝 [LiveReload - browser extensions](http://feedback.livereload.com/knowledgebase/articles/86242-how-do-i-install-and-use-the-browser-extensions-) -支援主流瀏覽器: +支援主流瀏覽器: Firefox, Chrome, Safari -* Firefox -* Chrome -* Safari - -### 安裝phpdoc - - pear channel-discover pear.phpdoc.org - pear install phpdoc/phpDocumentor - -## 自動化建置 -很簡單,只要下以下指令即可啟動 +## 自動化建置 (開發前建議啟動) +撰寫程式前,可在專案內下以下指令即可啟動 guard @@ -54,6 +152,7 @@ TODO: 代補,需有`gem`, `phar` * phpdoc: 重新建立開發文件 * livereload: 呼叫瀏覽器自動重新整理 +* phpunit2: 單元測試是否可成功執行 #### 相關參考 * @@ -62,6 +161,16 @@ TODO: 代補,需有`gem`, `phar` ## 開發文件 已將整份專案使用[PHPDocumentor](http://www.phpdoc.org/)產生出[開發文件網站](docs/index.html) -產生指令(若有使用Guard的話可省略,會自動連同一起產生): +PS. 若有使用Guard的話可不需手動下此指令,會自動連同一起產生 + +產生指令: phpdoc -d ./htdocs/lib -t ./docs/ + +## 單元測試 +PS. 若有使用Guard的話,會自動對你正在編輯的檔案進行測試 + +測試指令: + + cd test # 進入測試資料夾 + phpunit --bootstrap ../htdocs/config.php <要測試的檔案> \ No newline at end of file From c77746bbf60edfac2bf3d10d75c59901af12b375 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Thu, 2 Oct 2014 18:19:32 +0800 Subject: [PATCH 26/35] Create User Class --- htdocs/config.sample.php | 7 + htdocs/lib/Database/DBUser.php | 124 +++++++++- htdocs/lib/User/User.php | 428 ++++++++++++++++++++++++++++++++- htdocs/lib/User/UserAdmin.php | 9 +- htdocs/lib/Util/Password.php | 19 +- tests/User/UserAdminTest.php | 2 - tests/Util/PasswordTest.php | 2 +- 7 files changed, 567 insertions(+), 24 deletions(-) diff --git a/htdocs/config.sample.php b/htdocs/config.sample.php index 8f82bbb..871814d 100644 --- a/htdocs/config.sample.php +++ b/htdocs/config.sample.php @@ -1,4 +1,11 @@ insertUser('eric', 'passwd', 'user', null, 1, 'harf-line-learn', '1', '偉人', 'Eric Chiou', 'eric@example.com', null); + * + * echo 'Finish'; + * } + * + * + * // 若設定的DBMS不被支援 則丟出例外 + * catch (Database\Exception\DatabaseNoSupportException $e) { + * echo 'No Support in ', $e->getType(); + * } catch (Exception $e) { + * echo 'Caught other exception: ', $e->getMessage(); + * echo '

    '. $e->getCode() .'

    '; + * } + * + * @param string $uId 使用者名稱 * @param string $password 密碼 - * @param string $gId 群組 - * @param string $cId 班級 - * @param string $enable 啟用此帳號 - * @param string $l_mode 學習模式 - * @param string $m_mode 教材模式 + * @param string $gId 群組 + * @param string $cId 班級 + * @param string $enable 啟用此帳號 + * @param string $l_mode 學習模式 + * @param string $m_mode 教材模式 * @param string $nickName 暱稱 * @param string $realName 姓名 - * @param string $email 電子郵件地址 - * @param string $memo 備註 + * @param string $email 電子郵件地址 + * @param string $memo 備註 */ public function insertUser($uId, $password, $gId, $cId, $enable, $l_mode, $m_mode, @@ -75,8 +99,47 @@ class DBUser extends Database { /** * 查詢一位使用者帳號資料 + * + * + * 範例: + * + * require_once __DIR__.'/../config.php'; + * require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; + * use UElearning\Database; + * + * try { + * $db = new Database\DBUser(); + * + * $userInfo = $db->queryUser('yuan'); + * echo '
    '; print_r($userInfo); echo '
    '; + * } + * + * + * // 若設定的DBMS不被支援 則丟出例外 + * catch (Database\Exception\DatabaseNoSupportException $e) { + * echo 'No Support in ', $e->getType(); + * } catch (Exception $e) { + * echo 'Caught other exception: ', $e->getMessage(); + * echo '

    '. $e->getCode() .'

    '; + * } + * * @param string $uId 使用者名稱 - * @return array 使用者資料 (TODO 格式待補) + * @return array 使用者資料陣列,格式為: + * array( + * 'user_id' => <帳號名稱>, + * 'password' => <密碼>, + * 'group_id' => <群組>, + * 'class_id' => <班級>, + * 'enable' => <啟用>, + * 'build_time' => <建立日期>, + * 'learnStyle_mode' => <偏好學習導引模式>, + * 'material_mode' => <偏好教材模式>, + * 'nickname' => <暱稱>, + * 'realname' => <真實姓名>, + * 'email' => <電子郵件地址>, + * 'memo' => <備註> + * ); + * */ public function queryUser($uId) { @@ -113,6 +176,49 @@ class DBUser extends Database { } } + /** + * 修改一位使用者的資料內容 + * + * 範例: + * + * $db = new Database\DBUser(); + * $db->changeUserData('yuan', 'memo', 'hahaha'); + * + * @param string $uId 使用者名稱 + * @param string $field 欄位名稱 + * @param string $value 內容 + */ + public function changeUserData($uId, $field, $value) { + // UPDATE `UElearning`.`chu__User` SET `UMemo` = '測試者' WHERE `chu__User`.`UID` = 'yuan'; + + $sqlField = null; + switch($field) { + case 'user_id': $sqlField = 'UID'; break; + case 'password': $sqlField = 'UPassword'; break; + case 'group_id': $sqlField = 'GID'; break; + case 'class_id': $sqlField = 'CID'; break; + case 'enable': $sqlField = 'UEnabled'; break; + case 'build_time': $sqlField = 'UBuild_Time'; break; + case 'learnStyle_mode': $sqlField = 'LMode'; break; + case 'material_mode': $sqlField = 'MMode'; break; + case 'nickname': $sqlField = 'UNickname'; break; + case 'realname': $sqlField = 'UReal_Name'; break; + case 'email': $sqlField = 'UEmail'; break; + case 'memo': $sqlField = 'UMemo'; break; + default: $sqlField = $field; break; + } + + + $sqlString = "UPDATE ".$this->table('User'). + " SET `".$sqlField."` = :value". + " WHERE `UID` = :uid"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':uid', $uId); + $query->bindParam(':value', $value); + $query->execute(); + } + /** * 移除一位使用者 * @param string $uId 使用者名稱 diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php index 78cb79a..1804497 100644 --- a/htdocs/lib/User/User.php +++ b/htdocs/lib/User/User.php @@ -5,4 +5,430 @@ namespace UElearning\User; -// TODO: write this code \ No newline at end of file +require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; +require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Util/Password.php'; +use UElearning\Database; +use UElearning\Util; + +/** + * 使用者處理專用類別 + * + * 一個物件即代表這一位使用者 + * + * 建立此物件範例: + * + * require_once __DIR__.'/../config.php'; + * require_once UELEARNING_LIB_ROOT.'/User/User.php'; + * use UElearning\User; + * + * try { + * $user = new User\User('yuan'); + * // TODO: 在這邊寫下要針對這位使用者作什麼事? + * } + * catch (User\Exception\UserNoFoundException $e) { + * echo 'No Found user: '. $e->getUserId(); + * } + * + * @version 2.0.0 + * @package UElearning + * @subpackage User + */ +class User { + + /** + * 使用者ID + * @type string + */ + protected $uId; + + // ------------------------------------------------------------------------ + + /** + * 查詢到此帳號的所有資訊的結果 + * + * 由 $this->getQuery() 抓取資料表中所有資訊,並放在此陣列裡 + * @type array + */ + protected $queryResultArray; + + /** + * 從資料庫取得此帳號查詢 + * + * @throw UElearning\User\Exception\UserNoFoundException + * @since 2.0.0 + */ + protected function getQuery(){ + // 從資料庫查詢使用者 + $db = new Database\DBUser(); + $userInfo = $db->queryUser($this->uId); + + // 判斷有沒有這位使用者 + if( $userInfo != null ) { + $this->queryResultArray = $userInfo; + } + else throw new Exception\UserNoFoundException($this->uId); + } + + /** + * 從資料庫更新此帳號設定 + * + * @since 2.0.0 + */ + protected function setUpdate($field, $value){ + /// 將新設定寫進資料庫裡 + $db = new Database\DBUser(); + $db->changeUserData($this->uId, $field, $value); + $this->getQuery(); + } + + + + // ======================================================================== + + /** + * 建構子 + * + * @param string $inputUID 使用者ID + * @since 2.0.0 + */ + public function __construct($inputUID){ + $this->uId = $inputUID; + $this->getQuery(); + } + + // ======================================================================== + + /** + * 取得帳號名稱 + * + * @return string 帳號名稱 + * @since 2.0.0 + */ + public function getUsername(){ + return $this->uId; + } + + // ------------------------------------------------------------------------ + + /** + * 驗證密碼是否錯誤 + * + * @param string $inputPasswd 密碼 + * @return bool true:密碼正確,false:密碼錯誤 + * @since 2.0.0 + */ + public function isPasswordCorrect($inputPasswd){ + $passUtil = new Util\Password(); + $this_passwd = $this->queryResultArray['password']; + return $passUtil->checkSame($this_passwd, $inputPasswd); + } + + /** + * 更改密碼 + * + * @param string $newPasswd 新密碼 + * @param string $newPasswdMode 新密碼加密方式(可省略) + * @return string 狀態回傳 + * @since 2.0.0 + */ + public function changePassword($newPasswd){ + // 進行密碼加密 + $passUtil = new Util\Password(); + $passwdEncrypted = $passUtil->encrypt($newPasswd); + + // 將新密碼寫進資料庫裡 + $this->setUpdate('password', $passwdEncrypted); + } + + // ======================================================================== + + /** + * 取得帳號建立時間 + * + * @return string 建立時間 + * @since 2.0.0 + */ + public function getCreateTime(){ + return $this->queryResultArray['build_time']; + } + // ======================================================================== + + /** + * 取得所在群組 + * + * @return string 群組ID + * @since 2.0.0 + */ + public function getGroup(){ + return $this->queryResultArray['group_id']; + } + + /** + * 取得所在群組顯式名稱 + * + * @return string 群組名稱 + * @since 2.0.0 + */ + public function getGroupName(){ + // TODO: getGroupName + } + + /** + * 設定所在群組 + * + * @param string $toGroup 群組ID + * @since 2.0.0 + */ + public function setGroup($toGroup){ + // TODO: setGroup + + + } + + // ------------------------------------------------------------------------ + + /** + * 取得所在班級 + * + * @return string 班級ID + * @since 2.0.0 + */ + public function getClass(){ + return $this->queryResultArray['class_id']; + } + + /** + * 取得所在群組顯式名稱 + * + * @return string 班級名稱 + * @since 2.0.0 + */ + public function getClassName(){ + // TODO: getGroupName + } + + /** + * 設定所在群組 + * + * @param string $toGroup 班級ID + * @since 2.0.0 + */ + public function setClass($toClass){ + // TODO: setGroup + + + } + + // ======================================================================== + + /** + * 取得帳號啟用狀態 + * + * @return bool 是否已啟用 + * @since 2.0.0 + */ + public function isEnable(){ + return $this->queryResultArray['enable']; + } + + /** + * 設定帳號啟用狀態 + * + * @param bool $isActive 是否為啟用 + * @since 2.0.0 + */ + public function setEnable($isActive){ + // TODO: 防呆,至少一個帳號是啟用的 + + // 將新設定寫進資料庫裡 + $this->setUpdate('enable', $isActive); + } + + // ======================================================================== + + /** + * 取得這個人的學習導引風格 + * + * @return string 學習導引風格 + * @since 2.0.0 + */ + public function getLearnStyle(){ + // TODO: + } + + /** + * 設定這個人的學習導引風格 + * + * @param string $style 學習導引風格 + * @since 2.0.0 + */ + public function setLearnStyle($style){ + // TODO + + + } + + /** + * 取得這個人的教材風格 + * + * @return string 教材風格 + * @since 2.0.0 + */ + public function getMaterialStyle(){ + // TODO: + } + + /** + * 設定這個人的教材風格 + * + * @param string $style 教材風格 + * @since 2.0.0 + */ + public function setMaterialStyle($style){ + // TODO + + + } + + // ======================================================================== + + /** + * 取得名稱 + * + * @return string 依照有填入多少名字
    優先順序: 暱稱→真實名字→帳號名稱 + * @since 2.0.0 + */ + public function getName(){ + // TODO: 代修正 + if($this->getNickName() != "") { + return $this->getNickName(); + } + else if($this->getRealName() != "") { + return $this->getRealName(); + } + else { + return $this->getUsername(); + } + } + + // ------------------------------------------------------------------------ + + /** + * 取得暱稱 + * + * @return string 暱稱 + * @since 2.0.0 + */ + public function getNickName(){ + return $this->queryResultArray['nickname']; + } + + /** + * 修改暱稱 + * + * @param string $input 新暱稱 + * @since 2.0.0 + */ + public function setNickName($input){ + // 將新設定寫進資料庫裡 + $this->setUpdate('nickname', $input); + } + + // ------------------------------------------------------------------------ + + /** + * 取得真實姓名 + * + * @return string 真實姓名 + * @since 2.0.0 + */ + public function getRealName(){ + return $this->queryResultArray['realname']; + } + + /** + * 修改真實姓名 + * + * @param string $input 新真實姓名 + * @since 2.0.0 + */ + public function setRealName($input){ + // 將新設定寫進資料庫裡 + $this->setUpdate('realname', $input); + } + + // ------------------------------------------------------------------------ + + /** + * 取得帳號Email + * + * @return string 使用者資訊的Email + * @since 2.0.0 + */ + public function getEmail(){ + return $this->queryResultArray['email']; + } + + /** + * 修改帳號Email + * + * @param string $input 新Email + * @since 2.0.0 + */ + public function setEmail($input){ + // 將新設定寫進資料庫裡 + $db->changeUserData($this->uId, 'email', $input); + } + + // ------------------------------------------------------------------------ + + /** + * 取得帳號備註資訊 + * + * @return string 使用者帳號備註資訊 + * @since 2.0.0 + */ + public function getMemo(){ + return $this->queryResultArray['memo']; + } + + /** + * 修改帳號備註資訊 + * + * @param string $input 新的帳號備註資訊 + * @since 2.0.0 + */ + public function setMemo($input){ + $this->setUpdate('memo', $input); + } + + // ======================================================================== + + /** + * 取得權限清單 + * + * @access public + * @return array 權限清單 + */ + public function getPermissionList() { + $thisGroup = new UserGroup($this->getQueryInfo("GID")); + return $thisGroup->getPermissionList(); + + } + + /** + * 是否擁有此權限 + * + * @access public + * @global string $FORM_USER 在/config/db_table_config.php的使用者資料表名稱 + * @global string $FORM_USER_GROUP 在/config/db_table_config.php的使用者群組資料表名稱 + * @param string $permissionName 權限名稱 + * @return bool 是否擁有 + */ + public function havePermission($permissionName) { + // TODO + } + +} \ No newline at end of file diff --git a/htdocs/lib/User/UserAdmin.php b/htdocs/lib/User/UserAdmin.php index cff0cfa..a6cfe70 100644 --- a/htdocs/lib/User/UserAdmin.php +++ b/htdocs/lib/User/UserAdmin.php @@ -8,7 +8,9 @@ namespace UElearning\User; require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; require_once UELEARNING_LIB_ROOT.'/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Util/Password.php'; use UElearning\Database; +use UElearning\Util; /** * 管理使用者的操作 @@ -105,11 +107,8 @@ class UserAdmin { } // 進行密碼加密 - /*if( isset($userInfoArray['userId']) ) { - // TODO: 密碼加密 - }*/ - // 加密後的密碼 - $passwdEncrypted = $userInfoArray['password']; + $passUtil = new Util\Password(); + $passwdEncrypted = $passUtil->encrypt( $userInfoArray['password'] ); // 新增一筆使用者資料進資料庫 $db = new Database\DBUser(); diff --git a/htdocs/lib/Util/Password.php b/htdocs/lib/Util/Password.php index 2bd5b45..111f108 100644 --- a/htdocs/lib/Util/Password.php +++ b/htdocs/lib/Util/Password.php @@ -8,6 +8,18 @@ namespace UElearning\Util; /** * 密碼以及加密相關的函式庫 * + * 使用範例: + * + * require_once __DIR__.'/../config.php'; + * require_once UELEARNING_LIB_ROOT.'/Util/Password.php'; + * use UElearning\Util; + * + * $passUtil = new Util\Password(); + * echo $passUtil->generator(10); // 產生10個字的密碼 + * echo $passUtil->encrypt('abc'); // 加密此字串 + * + * // 核對與加密後是否吻合 + * echo $passUtil->checkSame('a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'); * * @author Yuan Chiu * @version 2.0.0 @@ -47,8 +59,7 @@ class Password { * @return string 亂數產生產生後的字串 * */ - public function generator($password_len) - { + public function generator($password_len){ $password = ''; // remove o,0,1,l @@ -70,8 +81,6 @@ class Password { * @since 2.0.0 */ public function encrypt($text){ - // TODO: 尚未測試 - // 從config.php設定檔取得預設加密方式 switch(ENCRYPT_MODE){ case "MD5": @@ -101,8 +110,6 @@ class Password { * @since 2.0.0 */ public function checkSame($encrypted, $text) { - // TODO: 尚未測試 - // 加密此字串 $textToEncypt = $this->encrypt($text); diff --git a/tests/User/UserAdminTest.php b/tests/User/UserAdminTest.php index b3c8212..ff3a387 100644 --- a/tests/User/UserAdminTest.php +++ b/tests/User/UserAdminTest.php @@ -31,8 +31,6 @@ class UserAdminTest extends \PHPUnit_Framework_TestCase $userAdmin->create( array( 'user_id' => $uId, 'password' => $uPassword, - //'password_encrypt' => null, - //'password_encrypted' => null, 'group_id' => $gId, 'class_id' => $cId, 'enable' => $enable, diff --git a/tests/Util/PasswordTest.php b/tests/Util/PasswordTest.php index 8783c61..ad38b10 100644 --- a/tests/Util/PasswordTest.php +++ b/tests/Util/PasswordTest.php @@ -25,7 +25,7 @@ class PasswordTest extends \PHPUnit_Framework_TestCase * * @dataProvider pass_dataProvider */ - public function testCheckSame($data){ + public function testCheckSame($value){ // 加密字串 $encode = $this->passUtil->encrypt($value); From f724d778200551151e477c669b74433954fe6b6c Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Fri, 3 Oct 2014 02:45:27 +0800 Subject: [PATCH 27/35] =?UTF-8?q?User=20=E6=94=B9=E8=89=AF=20&=20GroupAdmi?= =?UTF-8?q?n=E5=BB=BA=E7=AB=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/lib/User/User.php | 5 +- htdocs/lib/User/UserGroupAdmin.php | 154 ++++++++++++++++++++++++++++- tests/Database/DBUserTest.php | 31 ++++++ tests/User/UserAdminTest.php | 2 +- tests/User/UserTest.php | 152 ++++++++++++++++++++++++++++ 5 files changed, 340 insertions(+), 4 deletions(-) create mode 100644 tests/User/UserTest.php diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php index 1804497..7e5d6f7 100644 --- a/htdocs/lib/User/User.php +++ b/htdocs/lib/User/User.php @@ -230,7 +230,8 @@ class User { * @since 2.0.0 */ public function isEnable(){ - return $this->queryResultArray['enable']; + if($this->queryResultArray['enable'] == 0) return false; + else return true; } /** @@ -379,7 +380,7 @@ class User { */ public function setEmail($input){ // 將新設定寫進資料庫裡 - $db->changeUserData($this->uId, 'email', $input); + $this->setUpdate('email', $input); } // ------------------------------------------------------------------------ diff --git a/htdocs/lib/User/UserGroupAdmin.php b/htdocs/lib/User/UserGroupAdmin.php index 5a38ccc..e53db9c 100644 --- a/htdocs/lib/User/UserGroupAdmin.php +++ b/htdocs/lib/User/UserGroupAdmin.php @@ -4,4 +4,156 @@ */ namespace UElearning\User; -// TODO: write this code \ No newline at end of file + + +/** + * 管理使用者權限群組的操作 + * + * @author Yuan Chiu + * @version 2.0.0 + * @package UElearning + * @subpackage User + */ +class UserGroupAdmin { + + /** + * 建立群組 + * + * 建立使用者範例: + * + * try { + * $userAdmin = new User\UserAdmin(); + * $userAdmin->create( + * array( 'group_id' => 'student', + * 'name' => '學生', + * 'memo' => null, + * 'auth_server_admin' => false, + * 'auth_client_admin' => false + * )); + * + * } + * // 若已有重複帳號名稱 + * catch (User\Exception\GroupIdExistException $e) { + * echo 'Is exist group: ', $e->getGroupId(); + * } + * + * @param array $groupArray 使用者資訊陣列,格式為: + * array( 'group_id' => 'student', + * 'name' => '學生', + * 'memo' => null, // (optional) 預設為null + * 'auth_server_admin' => false, // (optional) 預設為false + * 'auth_client_admin' => false ) // (optional) 預設為false + * @throw UElearning\User\Exception\GroupIdExistException + * @since 2.0.0 + */ + public function create($groupArray) { + + /*// 檢查必填項目有無填寫 + if(isset($userInfoArray)) { + + // 若無填寫 + if( !isset($userInfoArray['user_id']) || + !isset($userInfoArray['password']) || + !isset($userInfoArray['group_id']) ) { + throw new UElearning\Exception\NoDataException(); + } + // 若此id已存在 + else if($this->isExist($userInfoArray['user_id'])) { + throw new Exception\UserIdExistException( + $userInfoArray['user_id'] ); + } + // 沒有問題 + else { + + // 處理未帶入的資料 + if( !isset($userInfoArray['class_id']) ){ + $userInfoArray['class_id'] = null; + } + if( !isset($userInfoArray['enable']) ){ + $userInfoArray['enable'] = true; + } + if( !isset($userInfoArray['learnStyle_mode']) ){ + $userInfoArray['learnStyle_mode'] = null; + } + if( !isset($userInfoArray['material_mode']) ){ + $userInfoArray['material_mode'] = null; + } + if( !isset($userInfoArray['nickname']) ){ + $userInfoArray['nickname'] = null; + } + if( !isset($userInfoArray['realname']) ){ + $userInfoArray['realname'] = null; + } + if( !isset($userInfoArray['email']) ){ + $userInfoArray['email'] = null; + } + if( !isset($userInfoArray['memo']) ){ + $userInfoArray['memo'] = null; + } + + // 進行密碼加密 + $passUtil = new Util\Password(); + $passwdEncrypted = $passUtil->encrypt( $userInfoArray['password'] ); + + // 新增一筆使用者資料進資料庫 + $db = new Database\DBUser(); + $db->insertUser( + $userInfoArray['user_id'], + $passwdEncrypted, + $userInfoArray['group_id'], + $userInfoArray['class_id'], + $userInfoArray['enable'], + $userInfoArray['learnStyle_mode'], + $userInfoArray['material_mode'], + $userInfoArray['nickname'], + $userInfoArray['realname'], + $userInfoArray['email'], + $userInfoArray['memo'] + ); + } + } + else throw Exception\NoDataException();*/ + } + + /** + * 是否已有相同名稱的帳號名稱 + * + * @param string $group_id 群組ID + * @return bool 已有相同的群組ID + * @since 2.0.0 + */ + public function isExist($group_id) { + + /*$db = new Database\DBUser(); + $info = $db->queryUser($userName); + + if( $info != null ) return true; + else return false;*/ + } + + /** + * 移除此群組 + * + * @param string $group_id 群組ID + * @throw UElearning\User\Exception\GroupNoFoundException + * @since 2.0.0 + */ + public function remove($group_id) { + /* + // 若有此使用者 + if($this->isExist($userName)) { + + // TODO: 檢查所有關聯的資料,確認是否可以移除 + + // 移除資料庫中的使用者 + $db = new Database\DBUser(); + $db->deleteUser($userName); + } + // 若沒有這位使用者 + else { + throw new Exception\UserNoFoundException($userName); + } + */ + } + +} \ No newline at end of file diff --git a/tests/Database/DBUserTest.php b/tests/Database/DBUserTest.php index 86a89ac..c0a582f 100644 --- a/tests/Database/DBUserTest.php +++ b/tests/Database/DBUserTest.php @@ -69,6 +69,37 @@ class DBUserTest extends \PHPUnit_Framework_TestCase $this->assertEquals($info['memo'], $memo); } + /** + * 測試更改使用者資料 + * + * @dataProvider userDataProvider + */ + public function testChangeUser($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo){ + + $afterData = 'sfisjojjoij'; + + // 記下更改前的資料 + $info = $this->db->queryUser($uId); + $beforeData = $info['memo']; + + // 更改資料 + $this->db->changeUserData($uId, 'memo', $afterData); + + // 檢查更改後的結果 + $info = $this->db->queryUser($uId); + $this->assertEquals($info['memo'], $afterData); + + // 改回來 + $this->db->changeUserData($uId, 'memo', $beforeData); + + // 檢查有沒有改回來 + $info = $this->db->queryUser($uId); + $this->assertEquals($info['memo'], $beforeData); + } + + /** * 測試移除使用者 * diff --git a/tests/User/UserAdminTest.php b/tests/User/UserAdminTest.php index ff3a387..d189a0c 100644 --- a/tests/User/UserAdminTest.php +++ b/tests/User/UserAdminTest.php @@ -14,7 +14,7 @@ class UserAdminTest extends \PHPUnit_Framework_TestCase { /** - * 測試安裝初始化資料庫 + * 測試建立使用者 * * @dataProvider userDataProvider */ diff --git a/tests/User/UserTest.php b/tests/User/UserTest.php new file mode 100644 index 0000000..b4e22fd --- /dev/null +++ b/tests/User/UserTest.php @@ -0,0 +1,152 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/User/User.php'; +require_once UELEARNING_LIB_ROOT.'/User/UserAdmin.php'; +use UElearning\User; + +class UserTest extends \PHPUnit_Framework_TestCase +{ + /** + * 測試建立使用者 + * + * @dataProvider userDataProvider + */ + public function testCreateUser($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo) + { + + try { + // 建立資料庫管理物件 + $userAdmin = new User\UserAdmin(); + + // TODO: 建立使用者 + $userAdmin->create( + array( 'user_id' => $uId, + 'password' => $uPassword, + 'group_id' => $gId, + 'class_id' => $cId, + 'enable' => $enable, + 'learnStyle_mode' => $l_mode, + 'material_mode' => $m_mode, + 'nickname' => $nickName, + 'realname' => $realName, + 'email' => $email, + 'memo' => $memo + )); + } + // 若設定的DBMS不被支援 則丟出例外 + catch (Database\Exception\DatabaseNoSupportException $e) { + throw $e; + } + } + + /** + * 測試取得資料 + * + * @dataProvider userDataProvider + */ + public function testGetInfo($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo) + { + try { + $user = new User\User($uId); + + // 密碼檢查 + $this->assertEquals($user->isPasswordCorrect($uPassword), true); + $this->assertEquals($user->isPasswordCorrect($uPassword.'as1@#'), false); + + // 個人資料檢查 + $this->assertEquals($user->getNickName(), $nickName); + $this->assertEquals($user->getRealName(), $realName); + $this->assertEquals($user->getEmail(), $email); + $this->assertEquals($user->getMemo(), $memo); + + } + catch (User\Exception\UserNoFoundException $e) { + echo 'No Found user: '. $e->getUserId(); + } + } + + /** + * 測試設定資料 + * + * @dataProvider userDataProvider + */ + public function testSetInfo($uId, $uPassword, $gId, $cId, $enable, + $l_mode, $m_mode, + $nickName, $realName, $email, $memo) + { + try { + $user = new User\User($uId); + + // 密碼檢查 + $user->changePassword('asdw'); + $this->assertEquals($user->isPasswordCorrect('asdw'), true); + + // 設定啟用檢查 + $user->setEnable(false); + $this->assertEquals($user->isEnable(), false); + + // 個人資料檢查 + $user->setNickName('叉洛伊'); + $this->assertEquals($user->getNickName(), '叉洛伊'); + + $user->setRealName('Eric Chiou'); + $this->assertEquals($user->getRealName(), 'Eric Chiou'); + + $user->setEmail('sdj@example.moe'); + $this->assertEquals($user->getEmail(), 'sdj@example.moe'); + + $user->setMemo('sacmldscmdlsvndlsknvkdsvne;vne;wnvoewzcmlsnwensc'); + $this->assertEquals($user->getMemo(), + 'sacmldscmdlsvndlsknvkdsvne;vne;wnvoewzcmlsnwensc'); + + } + catch (User\Exception\UserNoFoundException $e) { + echo 'No Found user: '. $e->getUserId(); + } + } + + /** + * 刪除建立的帳號(恢復原狀用) + * + * @dataProvider userDataProvider + */ + public function testDeleteUser($uId) + { + // 建立資料庫管理物件 + $userAdmin = new User\UserAdmin(); + + // 移除此使用者 + $userAdmin->remove($uId); + + // 檢查是否已確實建立 + $this->assertEquals($userAdmin->isExist($uId), false); + + } + + /** + * 測試時要填的資料 + */ + public function userDataProvider(){ + return array( + array('yuan_unittest', 'pass123', 'admin', null, true, + 'harf-line-learn', 1, + '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null), + + array('eee_unittest', 'qqqssss', 'admin', null, 1, + 'harf-line-learn', '1', + 'sss', 'Yuan Chiu', 'chyuanesr@gmail.com', null) + ); + } + +} \ No newline at end of file From f5b044e3b5d4ec0de748b8b6fd7b84c0694199c6 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Mon, 6 Oct 2014 16:42:59 +0800 Subject: [PATCH 28/35] Add UserGroupAdmin Class --- htdocs/lib/Database/DBUser.php | 219 +++++++++++++++++++++++++++-- htdocs/lib/User/Exception.php | 63 +++++++++ htdocs/lib/User/UserAdmin.php | 11 +- htdocs/lib/User/UserGroupAdmin.php | 104 +++++++------- tests/Database/DBUserTest.php | 59 ++++++++ tests/User/UserGroupAdminTest.php | 83 +++++++++++ 6 files changed, 467 insertions(+), 72 deletions(-) create mode 100644 tests/User/UserGroupAdminTest.php diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index 28402d1..af6d4f7 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -68,7 +68,7 @@ class DBUser extends Database { $nickName, $realName, $email, $memo){ // 檢查是否有支援所設定的DBMS - if($this->db_type == 'mysql') { + //if($this->db_type == 'mysql') { //紀錄使用者帳號進資料庫 $sqlString = "INSERT INTO ".$this->table('User'). @@ -90,13 +90,32 @@ class DBUser extends Database { $query->bindParam(":email", $email); $query->bindParam(":memo", $memo); $query->execute(); - } - else { - throw new Exception\DatabaseNoSupportException($this->db_type); - } + //} + //else { + // throw new Exception\DatabaseNoSupportException($this->db_type); + //} } + /** + * 移除一位使用者 + * @param string $uId 使用者名稱 + */ + public function deleteUser($uId) { + + //if($this->db_type == 'mysql') { + $sqlString = "DELETE FROM ".$this->table(self::FORM_USER). + " WHERE `UID` = :id "; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":id", $uId); + $query->execute(); + //} + //else { + // throw new Exception\DatabaseNoSupportException($this->db_type); + //} + } + /** * 查詢一位使用者帳號資料 * @@ -151,6 +170,7 @@ class DBUser extends Database { $query->execute(); $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 if( count($queryResultAll) >= 1 ) { $queryResult = $queryResultAll[0]; @@ -171,6 +191,66 @@ class DBUser extends Database { return $result; } + // 若都沒查到的話 + else { + return null; + } + } + + /** + * 查詢所有的使用者帳號資料 + * + * @return array 使用者資料陣列,格式為: + * + * array( + * array( + * 'user_id' => <帳號名稱>, + * 'password' => <密碼>, + * 'group_id' => <群組>, + * 'class_id' => <班級>, + * 'enable' => <啟用>, + * 'build_time' => <建立日期>, + * 'learnStyle_mode' => <偏好學習導引模式>, + * 'material_mode' => <偏好教材模式>, + * 'nickname' => <暱稱>, + * 'realname' => <真實姓名>, + * 'email' => <電子郵件地址>, + * 'memo' => <備註> + * ) + * ); + * + */ + public function queryAllUser() { + + $sqlString = "SELECT * FROM ".$this->table('User'); + + $query = $this->connDB->prepare($sqlString); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + // 製作回傳結果陣列 + $result = array(); + foreach($queryResultAll as $key => $thisResult) { + array_push($result, + array( 'user_id' => $thisResult['UID'], + 'password' => $thisResult['UPassword'], + 'group_id' => $thisResult['GID'], + 'class_id' => $thisResult['CID'], + 'enable' => $thisResult['UEnabled'], + 'build_time' => $thisResult['UBuild_Time'], + 'learnStyle_mode' => $thisResult['LMode'], + 'material_mode' => $thisResult['MMode'], + 'nickname' => $thisResult['UNickname'], + 'realname' => $thisResult['UReal_Name'], + 'email' => $thisResult['UEmail'], + 'memo' => $thisResult['UMemo']) + ); + } + return $result; + } + // 若都沒查到的話 else { return null; } @@ -219,23 +299,132 @@ class DBUser extends Database { $query->execute(); } + // ======================================================================== + /** - * 移除一位使用者 - * @param string $uId 使用者名稱 + * 插入群組資料 + * + * @param string $gId 群組ID + * @param string $name 群組顯示名稱 + * @param string $memo 備註 + * @param string $auth_admin Server端管理權 + * @param string $auth_clientAdmin Client端管理權 */ - public function deleteUser($uId) { + public function insertGroup($gId, $name, $memo, $auth_admin, $auth_clientAdmin) { - if($this->db_type == 'mysql') { - $sqlString = "DELETE FROM ".$this->table(self::FORM_USER). - " WHERE `UID` = :id "; + // 紀錄使用者帳號進資料庫 + $sqlString = "INSERT INTO ".$this->table('AGroup'). + " (`GID`, `GName`, `GMemo`, `GAuth_Admin`, `GAuth_ClientAdmin`) + VALUES ( :id , :name, :memo , :auth_admin , :auth_clientAdmin )"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":id", $gId); + $query->bindParam(":name", $name); + $query->bindParam(":memo", $memo); + $query->bindParam(":auth_admin", $auth_admin); + $query->bindParam(":auth_clientAdmin", $auth_clientAdmin); + $query->execute(); + } + + /** + * 移除一個使用者群組 + * @param string $gId + */ + public function deleteGroup($gId) { + + $sqlString = "DELETE FROM ".$this->table('AGroup'). + " WHERE `GID` = :id "; - $query = $this->connDB->prepare($sqlString); - $query->bindParam(":id", $uId); - $query->execute(); + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":id", $gId); + $query->execute(); + } + + /** + * 查詢一個使用者群組資料 + * + * @return array 使用者群組資料陣列,格式為: + * + * array( 'group_id' => <群組ID>, + * 'name' => <群組顯示名稱>, + * 'memo' => <備註>, + * 'auth_admin' => , + * 'auth_clientAdmin' => + * ); + * + */ + public function queryGroup($gId) { + + $sqlString = "SELECT * FROM ".$this->table('AGroup'). + " WHERE `GID` = :gid"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':gid', $gId); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + $thisResult = $queryResultAll[0]; + // 製作回傳結果陣列 + $result = array('group_id' => $thisResult['GID'], + 'name' => $thisResult['GName'], + 'memo' => $thisResult['GMemo'], + 'auth_admin' => $thisResult['GAuth_Admin'], + 'auth_clientAdmin' => $thisResult['GAuth_ClientAdmin'] + ); + return $result; } + // 若都沒查到的話 else { - throw new Exception\DatabaseNoSupportException($this->db_type); + return null; } } + /** + * 查詢所有的使用者群組資料 + * + * @return array 使用者群組資料陣列,格式為: + * + * array( + * array( + * 'group_id' => <群組ID>, + * 'name' => <群組顯示名稱>, + * 'memo' => <備註>, + * 'auth_admin' => , + * 'auth_clientAdmin' => + * ) + * ); + * + */ + public function queryAllGroup() { + + $sqlString = "SELECT * FROM ".$this->table('AGroup'); + + $query = $this->connDB->prepare($sqlString); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + // 製作回傳結果陣列 + $result = array(); + foreach($queryResultAll as $key => $thisResult) { + array_push($result, + array( 'group_id' => $thisResult['GID'], + 'name' => $thisResult['GName'], + 'memo' => $thisResult['GMemo'], + 'auth_admin' => $thisResult['GAuth_Admin'], + 'auth_clientAdmin' => $thisResult['GAuth_ClientAdmin']) + ); + } + return $result; + } + // 若都沒查到的話 + else { + return null; + } + } + + } \ No newline at end of file diff --git a/htdocs/lib/User/Exception.php b/htdocs/lib/User/Exception.php index 2d9b44e..ab1b3a9 100644 --- a/htdocs/lib/User/Exception.php +++ b/htdocs/lib/User/Exception.php @@ -95,3 +95,66 @@ class UserIdExistException extends UserException { parent::__construct($userId, 'UserId: "'.$userId.'" is exist.'); } } + +// ============================================================================ + +/** + * 使用者群組例外 + * @since 2.0.0 + * @package UElearning + * @subpackage User + */ +abstract class GroupException extends \UnexpectedValueException { + + /** + * 指定的使用者群組ID + * @type string + */ + private $groupId; + + /** + * 使用者帳號例外 + * @param string $groupId 輸入的使用者群組ID + * @param string $description 描述 + */ + public function __construct($groupId, $description) { + $this->groupId = $groupId; + parent::__construct($description); + } + + /** + * 取得輸入的資料庫系統名稱 + * @return string 錯誤訊息內容 + */ + public function getGroupId() { + return $this->groupId; + } +} + +/** + * 已有重複的使用者群組ID + * @since 2.0.0 + */ +class GroupIdExistException extends GroupException { + /** + * 已有重複的使用者名稱 + * @param string $groupId 輸入的使用者群組ID + */ + public function __construct($groupId) { + parent::__construct($groupId, 'GroupId: "'.$groupId.'" is exist.'); + } +} + +/** + * 沒有找到此使用者群組ID + * @since 2.0.0 + */ +class GroupNoFoundException extends GroupException { + /** + * 沒有找到此帳號 + * @param string $groupId 輸入的使用者群組ID + */ + public function __construct($groupId) { + parent::__construct($groupId, 'Group: "'.$groupId.'" is no found.'); + } +} \ No newline at end of file diff --git a/htdocs/lib/User/UserAdmin.php b/htdocs/lib/User/UserAdmin.php index a6cfe70..5df69f9 100644 --- a/htdocs/lib/User/UserAdmin.php +++ b/htdocs/lib/User/UserAdmin.php @@ -149,6 +149,16 @@ class UserAdmin { /** * 移除此使用者 * + * 範例: + * + * try { + * $userAdmin = new User\UserAdmin(); + * $userAdmin->remove('eric'); + * } + * catch (User\Exception\UserNoFoundException $e) { + * echo 'No Found user: ', $e->getUserId(); + * } + * * @param string $userName 帳號名稱 * @throw UElearning\User\Exception\UserNoFoundException * @since 2.0.0 @@ -168,7 +178,6 @@ class UserAdmin { else { throw new Exception\UserNoFoundException($userName); } - } } \ No newline at end of file diff --git a/htdocs/lib/User/UserGroupAdmin.php b/htdocs/lib/User/UserGroupAdmin.php index e53db9c..09ed50a 100644 --- a/htdocs/lib/User/UserGroupAdmin.php +++ b/htdocs/lib/User/UserGroupAdmin.php @@ -5,6 +5,10 @@ namespace UElearning\User; +require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; +require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Exception.php'; +use UElearning\Database; /** * 管理使用者權限群組的操作 @@ -22,8 +26,8 @@ class UserGroupAdmin { * 建立使用者範例: * * try { - * $userAdmin = new User\UserAdmin(); - * $userAdmin->create( + * $groupAdmin = new User\UserGroupAdmin(); + * $groupAdmin->create( * array( 'group_id' => 'student', * 'name' => '學生', * 'memo' => null, @@ -48,71 +52,48 @@ class UserGroupAdmin { */ public function create($groupArray) { - /*// 檢查必填項目有無填寫 - if(isset($userInfoArray)) { + // 檢查有無填寫 + if(isset($groupArray)) { - // 若無填寫 - if( !isset($userInfoArray['user_id']) || - !isset($userInfoArray['password']) || - !isset($userInfoArray['group_id']) ) { + // 若必填項目無填寫 + if( !isset($groupArray['group_id']) ) { throw new UElearning\Exception\NoDataException(); } // 若此id已存在 - else if($this->isExist($userInfoArray['user_id'])) { - throw new Exception\UserIdExistException( - $userInfoArray['user_id'] ); + else if( $this->isExist($groupArray['group_id']) ) { + throw new Exception\GroupIdExistException( + $groupArray['group_id'] ); } // 沒有問題 else { // 處理未帶入的資料 - if( !isset($userInfoArray['class_id']) ){ - $userInfoArray['class_id'] = null; + if( !isset($groupArray['name']) ){ + $groupArray['name'] = null; } - if( !isset($userInfoArray['enable']) ){ - $userInfoArray['enable'] = true; + // 處理未帶入的資料 + if( !isset($groupArray['memo']) ){ + $groupArray['memo'] = null; } - if( !isset($userInfoArray['learnStyle_mode']) ){ - $userInfoArray['learnStyle_mode'] = null; + if( !isset($groupArray['auth_server_admin']) ){ + $groupArray['auth_server_admin'] = false; } - if( !isset($userInfoArray['material_mode']) ){ - $userInfoArray['material_mode'] = null; + if( !isset($groupArray['auth_client_admin']) ){ + $groupArray['auth_client_admin'] = false; } - if( !isset($userInfoArray['nickname']) ){ - $userInfoArray['nickname'] = null; - } - if( !isset($userInfoArray['realname']) ){ - $userInfoArray['realname'] = null; - } - if( !isset($userInfoArray['email']) ){ - $userInfoArray['email'] = null; - } - if( !isset($userInfoArray['memo']) ){ - $userInfoArray['memo'] = null; - } - - // 進行密碼加密 - $passUtil = new Util\Password(); - $passwdEncrypted = $passUtil->encrypt( $userInfoArray['password'] ); // 新增一筆使用者資料進資料庫 $db = new Database\DBUser(); - $db->insertUser( - $userInfoArray['user_id'], - $passwdEncrypted, - $userInfoArray['group_id'], - $userInfoArray['class_id'], - $userInfoArray['enable'], - $userInfoArray['learnStyle_mode'], - $userInfoArray['material_mode'], - $userInfoArray['nickname'], - $userInfoArray['realname'], - $userInfoArray['email'], - $userInfoArray['memo'] + $db->insertGroup( + $groupArray['group_id'], + $groupArray['name'], + $groupArray['memo'], + $groupArray['auth_server_admin'], + $groupArray['auth_client_admin'] ); } } - else throw Exception\NoDataException();*/ + else throw Exception\NoDataException(); } /** @@ -124,36 +105,47 @@ class UserGroupAdmin { */ public function isExist($group_id) { - /*$db = new Database\DBUser(); - $info = $db->queryUser($userName); + $db = new Database\DBUser(); + $info = $db->queryGroup($group_id); if( $info != null ) return true; - else return false;*/ + else return false; } /** * 移除此群組 * + * 範例: + * + * try { + * $groupAdmin = new User\UserGroupAdmin(); + * $groupAdmin->remove('test_student'); + * + * } + * catch (User\Exception\GroupNoFoundException $e) { + * echo 'No Found group: ', $e->getGroupId(); + * } + * * @param string $group_id 群組ID * @throw UElearning\User\Exception\GroupNoFoundException * @since 2.0.0 */ public function remove($group_id) { - /* + // 若有此使用者 - if($this->isExist($userName)) { + if($this->isExist($group_id)) { // TODO: 檢查所有關聯的資料,確認是否可以移除 // 移除資料庫中的使用者 $db = new Database\DBUser(); - $db->deleteUser($userName); + $db->deleteGroup($group_id); } // 若沒有這位使用者 else { - throw new Exception\UserNoFoundException($userName); + throw new Exception\GroupNoFoundException($group_id); } - */ + } } \ No newline at end of file diff --git a/tests/Database/DBUserTest.php b/tests/Database/DBUserTest.php index c0a582f..ca065e3 100644 --- a/tests/Database/DBUserTest.php +++ b/tests/Database/DBUserTest.php @@ -69,6 +69,17 @@ class DBUserTest extends \PHPUnit_Framework_TestCase $this->assertEquals($info['memo'], $memo); } + /** + * 測試查詢所有使用者 + * + * 僅測試是否能成功執行,不驗證結果 + */ + public function testQueryAllUser(){ + + // 查詢使用者 + $infoAll = $this->db->queryAllUser(); + } + /** * 測試更改使用者資料 * @@ -123,4 +134,52 @@ class DBUserTest extends \PHPUnit_Framework_TestCase 'sss', 'Yuan Chiu', 'chyuanesr@gmail.com', null) ); } + + // ======================================================================== + + /** + * 測試建立群組 + * + * @dataProvider groupDataProvider + */ + public function testCreateGroup($gId, $name, $memo, $auth_admin, $auth_clientAdmin){ + + $this->db->insertGroup($gId, $name, $memo, $auth_admin, $auth_clientAdmin); + } + + /** + * 測試查詢群組 + * + * @dataProvider groupDataProvider + */ + public function testQueryGroup($gId, $name, $memo, $auth_admin, $auth_clientAdmin){ + // 查詢使用者 + $info = $this->db->queryGroup($gId); + + // 比對資料是否吻合 + $this->assertEquals($info['group_id'], $gId); + $this->assertEquals($info['name'], $name); + $this->assertEquals($info['memo'], $memo); + $this->assertEquals($info['auth_admin'], $auth_admin); + $this->assertEquals($info['auth_clientAdmin'], $auth_clientAdmin); + } + + /** + * 測試移除使用者 + * + * @dataProvider groupDataProvider + */ + public function testDeleteGroup($gId) { + $this->db->deleteGroup($gId); + } + + /** + * 測試時要填的資料 + */ + public function groupDataProvider(){ + return array( + array('testG_a', '測試用群組a', null, '1', '0'), + array('testG_b', '測試用群組b', 'testhahaha Groups', '0', '1') + ); + } } \ No newline at end of file diff --git a/tests/User/UserGroupAdminTest.php b/tests/User/UserGroupAdminTest.php new file mode 100644 index 0000000..0cd484c --- /dev/null +++ b/tests/User/UserGroupAdminTest.php @@ -0,0 +1,83 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/User/UserGroupAdmin.php'; +use UElearning\User\UserGroupAdmin; + +class UserGroupAdminTest extends \PHPUnit_Framework_TestCase +{ + + /** + * 測試建立群組 + * + * @dataProvider groupDataProvider + */ + public function testCreateGroup($gId, $name, $memo, $auth_admin, $auth_clientAdmin){ + + try { + $groupAdmin = new User\UserGroupAdmin(); + $groupAdmin->create( + array( 'group_id' => $gId, + 'name' => $name, + 'memo' => $memo, + 'auth_server_admin' => $auth_admin, + 'auth_client_admin' => $auth_clientAdmin + )); + + } + // 若已有重複帳號名稱 + catch (User\Exception\GroupIdExistException $e) { + throw $e; + } + + } + + /** + * 測試查詢群組 + * + * @dataProvider groupDataProvider + */ + public function testCheckExist($gId){ + + $groupAdmin = new User\UserGroupAdmin(); + + // 比對資料是否吻合 + $this->assertEquals($groupAdmin->isExist($gId), true); + } + + /** + * 測試移除使用者 + * + * @dataProvider groupDataProvider + */ + public function testDeleteGroup($gId) { + + try { + $groupAdmin = new User\UserGroupAdmin(); + $groupAdmin->remove($gId); + + $this->assertEquals($groupAdmin->isExist($gId), false); + } + catch (User\Exception\GroupNoFoundException $e) { + throw $e; + } + + } + + /** + * 測試時要填的資料 + */ + public function groupDataProvider(){ + return array( + array('testG_a', '測試用群組a', null, '1', '0'), + array('testG_b', '測試用群組b', 'testhahaha Groups', '0', '1') + ); + } + +} \ No newline at end of file From 311a47d9279b62933755ce233f61429394056354 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Tue, 7 Oct 2014 17:09:56 +0800 Subject: [PATCH 29/35] Add UserGroup Class --- htdocs/lib/Database/DBUser.php | 41 ++++++- htdocs/lib/User/User.php | 4 +- htdocs/lib/User/UserGroup.php | 188 ++++++++++++++++++++++++++++++++- tests/Database/DBUserTest.php | 27 +++++ 4 files changed, 254 insertions(+), 6 deletions(-) diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index af6d4f7..a422bee 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -314,8 +314,8 @@ class DBUser extends Database { // 紀錄使用者帳號進資料庫 $sqlString = "INSERT INTO ".$this->table('AGroup'). - " (`GID`, `GName`, `GMemo`, `GAuth_Admin`, `GAuth_ClientAdmin`) - VALUES ( :id , :name, :memo , :auth_admin , :auth_clientAdmin )"; + " (`GID`, `GName`, `GMemo`, `GBuild_Time`, `GAuth_Admin`, `GAuth_ClientAdmin`) + VALUES ( :id , :name, :memo , NOW(), :auth_admin , :auth_clientAdmin )"; $query = $this->connDB->prepare($sqlString); $query->bindParam(":id", $gId); @@ -370,6 +370,7 @@ class DBUser extends Database { $result = array('group_id' => $thisResult['GID'], 'name' => $thisResult['GName'], 'memo' => $thisResult['GMemo'], + 'build_time' => $thisResult['GBuild_Time'], 'auth_admin' => $thisResult['GAuth_Admin'], 'auth_clientAdmin' => $thisResult['GAuth_ClientAdmin'] ); @@ -414,6 +415,7 @@ class DBUser extends Database { array( 'group_id' => $thisResult['GID'], 'name' => $thisResult['GName'], 'memo' => $thisResult['GMemo'], + 'build_time' => $thisResult['GBuild_Time'], 'auth_admin' => $thisResult['GAuth_Admin'], 'auth_clientAdmin' => $thisResult['GAuth_ClientAdmin']) ); @@ -426,5 +428,40 @@ class DBUser extends Database { } } + /** + * 修改一個群組的資料內容 + * + * 範例: + * + * $db = new Database\DBUser(); + * $db->changeGroupData('student', 'name', '學生'); + * + * @param string $uId 使用者名稱 + * @param string $field 欄位名稱 + * @param string $value 內容 + */ + public function changeGroupData($gId, $field, $value) { + // UPDATE `UElearning`.`chu__User` SET `UMemo` = '測試者' WHERE `chu__User`.`UID` = 'yuan'; + + $sqlField = null; + switch($field) { + case 'group_id': $sqlField = 'UID'; break; + case 'name': $sqlField = 'GName'; break; + case 'memo': $sqlField = 'GMemo'; break; + case 'auth_admin': $sqlField = 'GAuth_Admin'; break; + case 'auth_clientAdmin': $sqlField = 'GAuth_ClientAdmin'; break; + default: $sqlField = $field; break; + } + + + $sqlString = "UPDATE ".$this->table('AGroup'). + " SET `".$sqlField."` = :value". + " WHERE `GID` = :gid"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':gid', $gId); + $query->bindParam(':value', $value); + $query->execute(); + } } \ No newline at end of file diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php index 7e5d6f7..e466d11 100644 --- a/htdocs/lib/User/User.php +++ b/htdocs/lib/User/User.php @@ -83,8 +83,6 @@ class User { $this->getQuery(); } - - // ======================================================================== /** @@ -166,7 +164,7 @@ class User { } /** - * 取得所在群組顯式名稱 + * 取得所在群組顯示名稱 * * @return string 群組名稱 * @since 2.0.0 diff --git a/htdocs/lib/User/UserGroup.php b/htdocs/lib/User/UserGroup.php index 857b05f..f17f32b 100644 --- a/htdocs/lib/User/UserGroup.php +++ b/htdocs/lib/User/UserGroup.php @@ -4,4 +4,190 @@ */ namespace UElearning\User; -// TODO: write this code \ No newline at end of file + +require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; +require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Exception.php'; +use UElearning\Database; + +/** + * 使用者群組類別 + * + * 一個物件即代表這一個使用者群組 + * + * 範例: + * + * try { + * $group = new User\UserGroup('testG'); + * echo $group->getName(); + * $group->setName('測試用'); + * echo $group->getName(); + * } + * catch (User\Exception\GroupNoFoundException $e) { + * echo 'No Found group: '. $e->getGroupId(); + * } + * + * @version 2.0.0 + * @package UElearning + * @subpackage User + */ +class UserGroup { + + /** + * 群組ID + * @type string + */ + protected $gId; + + // ======================================================================== + + /** + * 查詢到此帳號的所有資訊的結果 + * + * 由 $this->getQuery() 抓取資料表中所有資訊,並放在此陣列裡 + * @type array + */ + protected $queryResultArray; + + /** + * 從資料庫取得此群組查詢 + * + * @throw UElearning\User\Exception\GroupNoFoundException + * @since 2.0.0 + */ + protected function getQuery(){ + // 從資料庫查詢群組 + $db = new Database\DBUser(); + $groupInfo = $db->queryGroup($this->gId); + + // 判斷有沒有這個群組 + if( $groupInfo != null ) { + $this->queryResultArray = $groupInfo; + } + else throw new Exception\GroupNoFoundException($this->gId); + } + + /** + * 從資料庫更新此群組設定 + * + * @since 2.0.0 + */ + protected function setUpdate($field, $value){ + /// 將新設定寫進資料庫裡 + $db = new Database\DBUser(); + $db->changeGroupData($this->gId, $field, $value); + $this->getQuery(); + } + + // ======================================================================== + + /** + * 建構子 + * + * @param string $inputGID 群組ID + * @since 2.0.0 + */ + public function __construct($inputGID){ + $this->gId = $inputGID; + $this->getQuery(); + } + + // ======================================================================== + + /** + * 取得群組ID + * + * @return string 群組ID + * @since 2.0.0 + */ + public function getID(){ + return $this->gId; + } + + // ------------------------------------------------------------------------ + + /** + * 取得帳號建立時間 + * + * @return string 建立時間 + * @since 2.0.0 + */ + public function getCreateTime(){ + return $this->queryResultArray['build_time']; + } + // ======================================================================== + + /** + * 取得群組顯示名稱 + * + * @return string 群組名稱 + * @since 2.0.0 + */ + public function getName(){ + return $this->queryResultArray['name']; + } + + /** + * 設定群組顯示名稱 + * + * @param string $name 群組名稱 + * @since 2.0.0 + */ + public function setName($name){ + // 將新設定寫進資料庫裡 + $this->setUpdate('name', $name); + } + + /** + * 取得帳號備註資訊 + * + * @return string 使用者帳號備註資訊 + * @since 2.0.0 + */ + public function getMemo(){ + return $this->queryResultArray['memo']; + } + + /** + * 修改帳號備註資訊 + * + * @param string $input 新的帳號備註資訊 + * @since 2.0.0 + */ + public function setMemo($input){ + $this->setUpdate('memo', $input); + } + + // ======================================================================== + + /** + * 取得權限清單 + * + * @return array 權限清單 + */ + public function getPermissionList() { + // TODO: 取得權限清單 + + } + + /** + * 是否擁有此權限 + * + * @param string $permissionName 權限名稱 + * @return bool 是否擁有 + */ + public function havePermission($permissionName) { + // TODO: 是否擁有此權限 + } + + /** + * 設定擁有此權限 + * + * @param string $permissionName 權限名稱 + * @return bool 是否擁有 + */ + public function setPermission($permissionName, $setBool) { + // TODO: 設定擁有此權限 + } + +} \ No newline at end of file diff --git a/tests/Database/DBUserTest.php b/tests/Database/DBUserTest.php index ca065e3..23b35ed 100644 --- a/tests/Database/DBUserTest.php +++ b/tests/Database/DBUserTest.php @@ -164,6 +164,33 @@ class DBUserTest extends \PHPUnit_Framework_TestCase $this->assertEquals($info['auth_clientAdmin'], $auth_clientAdmin); } + /** + * 測試修改群組 + * + * @dataProvider groupDataProvider + */ + public function testChangeGroup($gId, $name, $memo, $auth_admin, $auth_clientAdmin){ + $afterData = 'sfisjojjoij'; + + // 記下更改前的資料 + $info = $this->db->queryGroup($gId); + $beforeData = $info['memo']; + + // 更改資料 + $this->db->changeGroupData($gId, 'memo', $afterData); + + // 檢查更改後的結果 + $info = $this->db->queryGroup($gId); + $this->assertEquals($info['memo'], $afterData); + + // 改回來 + $this->db->changeGroupData($gId, 'memo', $beforeData); + + // 檢查有沒有改回來 + $info = $this->db->queryGroup($gId); + $this->assertEquals($info['memo'], $beforeData); + } + /** * 測試移除使用者 * From d17829031c06fd2d97ca4afd63b10de51a72c89c Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Tue, 7 Oct 2014 17:19:02 +0800 Subject: [PATCH 30/35] Add UserGroup Test Class --- tests/User/UserGroupTest.php | 114 +++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/User/UserGroupTest.php diff --git a/tests/User/UserGroupTest.php b/tests/User/UserGroupTest.php new file mode 100644 index 0000000..a45c8e7 --- /dev/null +++ b/tests/User/UserGroupTest.php @@ -0,0 +1,114 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/User/UserGroup.php'; +require_once UELEARNING_LIB_ROOT.'/User/UserGroupAdmin.php'; +use UElearning\User; + +class UserGroupTest extends \PHPUnit_Framework_TestCase +{ + /** + * 測試建立群組 + * + * @dataProvider groupDataProvider + */ + public function testCreateGroup($gId, $name, $memo, $auth_admin, $auth_clientAdmin){ + + try { + $groupAdmin = new User\UserGroupAdmin(); + $groupAdmin->create( + array( 'group_id' => $gId, + 'name' => $name, + 'memo' => $memo, + 'auth_server_admin' => $auth_admin, + 'auth_client_admin' => $auth_clientAdmin + )); + + } + // 若已有重複帳號名稱 + catch (User\Exception\GroupIdExistException $e) { + throw $e; + } + + } + + /** + * 測試取得資料 + * + * @dataProvider groupDataProvider + */ + public function testGetInfo($gId, $name, $memo, $auth_admin, $auth_clientAdmin) + { + try { + $user = new User\UserGroup($gId); + + // 個人資料檢查 + $this->assertEquals($user->getName(), $name); + $this->assertEquals($user->getMemo(), $memo); + + } + catch (User\Exception\GroupNoFoundException $e) { + echo 'No Found group: '. $e->getGroupId(); + } + } + + /** + * 測試設定資料 + * + * @dataProvider groupDataProvider + */ + public function testSetInfo($gId, $name, $memo, $auth_admin, $auth_clientAdmin) + { + try { + $user = new User\UserGroup($gId); + + // 個人資料檢查 + $user->setName('叉洛伊'); + $this->assertEquals($user->getName(), '叉洛伊'); + + $user->setMemo('sacmldscmdlsvndlsknvkdsvne;vne;wnvoewzcmlsnwensc'); + $this->assertEquals($user->getMemo(), + 'sacmldscmdlsvndlsknvkdsvne;vne;wnvoewzcmlsnwensc'); + + } + catch (User\Exception\GroupNoFoundException $e) { + echo 'No Found group: '. $e->getGroupId(); + } + } + + /** + * 測試移除使用者 + * + * @dataProvider groupDataProvider + */ + public function testDeleteGroup($gId) { + + try { + $groupAdmin = new User\UserGroupAdmin(); + $groupAdmin->remove($gId); + + $this->assertEquals($groupAdmin->isExist($gId), false); + } + catch (User\Exception\GroupNoFoundException $e) { + throw $e; + } + + } + + /** + * 測試時要填的資料 + */ + public function groupDataProvider(){ + return array( + array('testG_a', '測試用群組a', null, '1', '0'), + array('testG_b', '測試用群組b', 'testhahaha Groups', '0', '1') + ); + } + +} \ No newline at end of file From 5c9477ce175f9299a6cd70b966803211da35f4e9 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Tue, 7 Oct 2014 17:22:38 +0800 Subject: [PATCH 31/35] UserGroup Doc --- htdocs/lib/User/UserGroup.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/lib/User/UserGroup.php b/htdocs/lib/User/UserGroup.php index f17f32b..169943a 100644 --- a/htdocs/lib/User/UserGroup.php +++ b/htdocs/lib/User/UserGroup.php @@ -17,6 +17,10 @@ use UElearning\Database; * * 範例: * + * require_once __DIR__.'/../config.php'; + * require_once UELEARNING_LIB_ROOT.'/User/UserGroup.php' + * use UElearning\User; + * * try { * $group = new User\UserGroup('testG'); * echo $group->getName(); From 5c7f8991ee961a2cda1fd76a45855118cdc87759 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Tue, 7 Oct 2014 18:12:02 +0800 Subject: [PATCH 32/35] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=80=85=E7=BE=A4?= =?UTF-8?q?=E7=B5=84=E5=92=8C=E4=BD=BF=E7=94=A8=E8=80=85=E9=A1=9E=E5=88=A5?= =?UTF-8?q?=E6=95=B4=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/lib/User/Exception.php | 35 ++++++++++++++ htdocs/lib/User/User.php | 89 ++++++++++++++++++++++++++--------- htdocs/lib/User/UserGroup.php | 51 +++++++++++++++++--- 3 files changed, 147 insertions(+), 28 deletions(-) diff --git a/htdocs/lib/User/Exception.php b/htdocs/lib/User/Exception.php index ab1b3a9..f9a294a 100644 --- a/htdocs/lib/User/Exception.php +++ b/htdocs/lib/User/Exception.php @@ -157,4 +157,39 @@ class GroupNoFoundException extends GroupException { public function __construct($groupId) { parent::__construct($groupId, 'Group: "'.$groupId.'" is no found.'); } +} + +// ============================================================================ + +/** + * 使用者群組例外 + * @since 2.0.0 + * @package UElearning + * @subpackage User + */ +class PermissionNoFoundException extends \UnexpectedValueException { + + /** + * 指定的使用者群組ID + * @type string + */ + private $permissionName; + + /** + * 使用者帳號例外 + * @param string $groupId 輸入的使用者群組ID + * @param string $description 描述 + */ + public function __construct($permissionName) { + $this->permissionName = $permissionName; + parent::__construct('No Found Permission: '.$this->permissionName); + } + + /** + * 取得輸入的資料庫系統名稱 + * @return string 錯誤訊息內容 + */ + public function getName() { + return $this->permissionName; + } } \ No newline at end of file diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php index e466d11..3b63e94 100644 --- a/htdocs/lib/User/User.php +++ b/htdocs/lib/User/User.php @@ -6,6 +6,8 @@ namespace UElearning\User; require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; +require_once UELEARNING_LIB_ROOT.'/User/UserGroupAdmin.php'; +require_once UELEARNING_LIB_ROOT.'/User/UserGroup.php'; require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; require_once UELEARNING_LIB_ROOT.'/Exception.php'; require_once UELEARNING_LIB_ROOT.'/Util/Password.php'; @@ -25,7 +27,11 @@ use UElearning\Util; * * try { * $user = new User\User('yuan'); - * // TODO: 在這邊寫下要針對這位使用者作什麼事? + * + * $user->changePassword('123456'); + * echo $user->isPasswordCorrect('123456'); + * + * echo 'NickName: '.$user->getNickName(); * } * catch (User\Exception\UserNoFoundException $e) { * echo 'No Found user: '. $e->getUserId(); @@ -102,6 +108,16 @@ class User { * 取得帳號名稱 * * @return string 帳號名稱 + * @since 2.0.0 + */ + public function getId(){ + return $this->uId; + } + + /** + * 取得帳號名稱 + * + * @return string 帳號名稱 * @since 2.0.0 */ public function getUsername(){ @@ -170,18 +186,52 @@ class User { * @since 2.0.0 */ public function getGroupName(){ - // TODO: getGroupName + + // 群組ID + $groupID = $this->queryResultArray['group_id']; + + // 取得群組名稱 + try { + $group = new User\UserGroup($groupID); + return $group->getName(); + } + catch (Exception\GroupNoFoundException $e) { + throw $e; + } } /** * 設定所在群組 * + * 範例: + * + * try { + * $user = new User\User('yuan'); + * try { + * $user->setGroup('student'); + * } + * catch (User\Exception\GroupNoFoundException $e) { + * echo 'No Group to set: '. $e->getGroupId(); + * } + * echo $user->getGroup(); + * } + * catch (User\Exception\UserNoFoundException $e) { + * echo 'No Found user: '. $e->getUserId(); + * } + * * @param string $toGroup 群組ID * @since 2.0.0 */ public function setGroup($toGroup){ - // TODO: setGroup + // 檢查有此群組 + $groupAdmin = new UserGroupAdmin(); + if($groupAdmin->isExist($toGroup)) { + $this->setUpdate('group_id', $toGroup); + } + else { + throw new Exception\GroupNoFoundException($toGroup); + } } @@ -198,13 +248,13 @@ class User { } /** - * 取得所在群組顯式名稱 + * 取得所在群組顯示名稱 * * @return string 班級名稱 * @since 2.0.0 */ public function getClassName(){ - // TODO: getGroupName + // TODO: 取得所在群組顯示名稱 } /** @@ -214,9 +264,7 @@ class User { * @since 2.0.0 */ public function setClass($toClass){ - // TODO: setGroup - - + // TODO: 設定所在群組 } // ======================================================================== @@ -254,7 +302,7 @@ class User { * @since 2.0.0 */ public function getLearnStyle(){ - // TODO: + // TODO: 取得這個人的學習導引風格 } /** @@ -264,7 +312,7 @@ class User { * @since 2.0.0 */ public function setLearnStyle($style){ - // TODO + // TODO: 設定這個人的學習導引風格 } @@ -276,7 +324,7 @@ class User { * @since 2.0.0 */ public function getMaterialStyle(){ - // TODO: + // TODO: 取得這個人的教材風格 } /** @@ -286,7 +334,7 @@ class User { * @since 2.0.0 */ public function setMaterialStyle($style){ - // TODO + // TODO: 設定這個人的教材風格 } @@ -300,7 +348,7 @@ class User { * @since 2.0.0 */ public function getName(){ - // TODO: 代修正 + // TODO: 待修正-取得名稱 if($this->getNickName() != "") { return $this->getNickName(); } @@ -408,26 +456,25 @@ class User { /** * 取得權限清單 * - * @access public * @return array 權限清單 + * @since 2.0.0 */ public function getPermissionList() { $thisGroup = new UserGroup($this->getQueryInfo("GID")); return $thisGroup->getPermissionList(); - } /** * 是否擁有此權限 * - * @access public - * @global string $FORM_USER 在/config/db_table_config.php的使用者資料表名稱 - * @global string $FORM_USER_GROUP 在/config/db_table_config.php的使用者群組資料表名稱 - * @param string $permissionName 權限名稱 - * @return bool 是否擁有 + * @param string $permissionName 權限名稱 + * @return bool 是否擁有 + * @throw UElearning\User\Exception\PermissionNoFoundException + * @since 2.0.0 */ public function havePermission($permissionName) { - // TODO + $thisGroup = new UserGroup($this->getQueryInfo("GID")); + return $thisGroup->havePermission($permissionName); } } \ No newline at end of file diff --git a/htdocs/lib/User/UserGroup.php b/htdocs/lib/User/UserGroup.php index 169943a..9a4380c 100644 --- a/htdocs/lib/User/UserGroup.php +++ b/htdocs/lib/User/UserGroup.php @@ -49,6 +49,7 @@ class UserGroup { * 查詢到此帳號的所有資訊的結果 * * 由 $this->getQuery() 抓取資料表中所有資訊,並放在此陣列裡 + * * @type array */ protected $queryResultArray; @@ -60,6 +61,7 @@ class UserGroup { * @since 2.0.0 */ protected function getQuery(){ + // 從資料庫查詢群組 $db = new Database\DBUser(); $groupInfo = $db->queryGroup($this->gId); @@ -77,6 +79,7 @@ class UserGroup { * @since 2.0.0 */ protected function setUpdate($field, $value){ + /// 將新設定寫進資料庫裡 $db = new Database\DBUser(); $db->changeGroupData($this->gId, $field, $value); @@ -138,7 +141,6 @@ class UserGroup { * @since 2.0.0 */ public function setName($name){ - // 將新設定寫進資料庫裡 $this->setUpdate('name', $name); } @@ -177,21 +179,56 @@ class UserGroup { /** * 是否擁有此權限 * - * @param string $permissionName 權限名稱 - * @return bool 是否擁有 + * @param string $permissionName 權限名稱 + * @return bool 是否擁有 + * @throw UElearning\User\Exception\PermissionNoFoundException + * @since 2.0.0 */ public function havePermission($permissionName) { - // TODO: 是否擁有此權限 + switch($permissionName) { + case 'server_admin': + case 'serverAdmin': + case 'ServerAdmin': + return $this->queryResultArray['auth_admin']; + break; + + case 'client_admin': + case 'clientAdmin': + case 'ClientAdmin': + return $this->queryResultArray['auth_clientAdmin']; + break; + + default: + throw new PermissionNoFoundException('$permissionName'); + return false; + } } /** * 設定擁有此權限 * - * @param string $permissionName 權限名稱 - * @return bool 是否擁有 + * @param string $permissionName 權限名稱 + * @param string $setBool 是否給予 + * @return bool 是否擁有 + * @throw UElearning\User\Exception\PermissionNoFoundException + * @since 2.0.0 */ public function setPermission($permissionName, $setBool) { - // TODO: 設定擁有此權限 + switch($permissionName) { + case 'server_admin': + case 'serverAdmin': + case 'ServerAdmin': + $this->setUpdate('auth_admin', $setBool); + break; + + case 'client_admin': + case 'clientAdmin': + case 'ClientAdmin': + $this->setUpdate('auth_clientAdmin', $setBool); + break; + default: + throw new PermissionNoFoundException('$permissionName'); + } } } \ No newline at end of file From 92b867ecb20a942dd82da833281d8f99be6d7517 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Wed, 8 Oct 2014 03:10:28 +0800 Subject: [PATCH 33/35] Add ClassGroup Class --- htdocs/lib/Database/DBUser.php | 217 ++++++++++++++++++++++++- htdocs/lib/User/ClassGroup.php | 164 ++++++++++++++++++- htdocs/lib/User/ClassGroupAdmin.php | 140 +++++++++++++++- htdocs/lib/User/Exception.php | 48 +++++- htdocs/lib/User/User.php | 3 +- htdocs/lib/User/UserGroupAdmin.php | 6 +- tests/Database/DBUserTest.php | 10 +- tests/User/ClassGroupAdminTest.php.bak | 92 +++++++++++ 8 files changed, 661 insertions(+), 19 deletions(-) create mode 100644 tests/User/ClassGroupAdminTest.php.bak diff --git a/htdocs/lib/Database/DBUser.php b/htdocs/lib/Database/DBUser.php index a422bee..f5d9aa9 100644 --- a/htdocs/lib/Database/DBUser.php +++ b/htdocs/lib/Database/DBUser.php @@ -174,12 +174,17 @@ class DBUser extends Database { if( count($queryResultAll) >= 1 ) { $queryResult = $queryResultAll[0]; + if($queryResult['UEnabled'] != '0') { + $output_enable = true; + } + else { $output_enable = false; } + $result = array( 'user_id' => $queryResult['UID'], 'password' => $queryResult['UPassword'], 'group_id' => $queryResult['GID'], 'class_id' => $queryResult['CID'], - 'enable' => $queryResult['UEnabled'], + 'enable' => $output_enable, 'build_time' => $queryResult['UBuild_Time'], 'learnStyle_mode' => $queryResult['LMode'], 'material_mode' => $queryResult['MMode'], @@ -233,12 +238,18 @@ class DBUser extends Database { // 製作回傳結果陣列 $result = array(); foreach($queryResultAll as $key => $thisResult) { + + if($thisResult['UEnabled'] != '0') { + $output_enable = true; + } + else { $output_enable = false; } + array_push($result, array( 'user_id' => $thisResult['UID'], 'password' => $thisResult['UPassword'], 'group_id' => $thisResult['GID'], 'class_id' => $thisResult['CID'], - 'enable' => $thisResult['UEnabled'], + 'enable' => $output_enable, 'build_time' => $thisResult['UBuild_Time'], 'learnStyle_mode' => $thisResult['LMode'], 'material_mode' => $thisResult['MMode'], @@ -366,13 +377,23 @@ class DBUser extends Database { // 如果有查到一筆以上 if( count($queryResultAll) >= 1 ) { $thisResult = $queryResultAll[0]; + + // 轉換成boolean + if($thisResult['GAuth_Admin'] != '0') { + $output_auth_admin = true; + } else { $output_auth_admin = false; } + + if($thisResult['GAuth_ClientAdmin'] != '0') { + $output_auth_clientAdmin = true; + } else { $output_auth_clientAdmin = false; } + // 製作回傳結果陣列 $result = array('group_id' => $thisResult['GID'], 'name' => $thisResult['GName'], 'memo' => $thisResult['GMemo'], 'build_time' => $thisResult['GBuild_Time'], - 'auth_admin' => $thisResult['GAuth_Admin'], - 'auth_clientAdmin' => $thisResult['GAuth_ClientAdmin'] + 'auth_admin' => $output_auth_admin, + 'auth_clientAdmin' => $output_auth_clientAdmin ); return $result; } @@ -411,13 +432,24 @@ class DBUser extends Database { // 製作回傳結果陣列 $result = array(); foreach($queryResultAll as $key => $thisResult) { + + // 轉換成boolean + if($thisResult['GAuth_Admin'] != '0') { + $output_auth_admin = true; + } else { $output_auth_admin = false; } + + if($thisResult['GAuth_ClientAdmin'] != '0') { + $output_auth_clientAdmin = true; + } else { $output_auth_clientAdmin = false; } + + // 插入一筆資料 array_push($result, array( 'group_id' => $thisResult['GID'], 'name' => $thisResult['GName'], 'memo' => $thisResult['GMemo'], 'build_time' => $thisResult['GBuild_Time'], - 'auth_admin' => $thisResult['GAuth_Admin'], - 'auth_clientAdmin' => $thisResult['GAuth_ClientAdmin']) + 'auth_admin' => $output_auth_admin, + 'auth_clientAdmin' => $output_auth_clientAdmin) ); } return $result; @@ -436,7 +468,7 @@ class DBUser extends Database { * $db = new Database\DBUser(); * $db->changeGroupData('student', 'name', '學生'); * - * @param string $uId 使用者名稱 + * @param string $gId 群組ID * @param string $field 欄位名稱 * @param string $value 內容 */ @@ -464,4 +496,175 @@ class DBUser extends Database { $query->execute(); } + // ======================================================================== + + /** + * 插入班級資料 + * + * @param string $cId 班級ID + * @param string $name 班級顯示名稱 + * @param string $memo 備註 + * @return int 剛剛新增的ID + */ + public function insertClassGroup($cId, $name, $memo) { + + // 紀錄使用者帳號進資料庫 + $sqlString = "INSERT INTO ".$this->table('CGroup'). + " (`CID`, `CName`, `CMemo`, `CBuild_Time`) + VALUES ( :id , :name, :memo , NOW() )"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":id", $cId); + $query->bindParam(":name", $name); + $query->bindParam(":memo", $memo); + $query->execute(); + + // 取得剛剛加入的ID + $sqlString = "SELECT LAST_INSERT_ID()"; + $query = $this->connDB->query($sqlString); + $queryResult = $query->fetch(); + return $queryResult[0]; + } + + /** + * 移除一個班級 + * @param string $cId + */ + public function deleteClassGroup($cId) { + + $sqlString = "DELETE FROM ".$this->table('CGroup'). + " WHERE `CID` = :id "; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":id", $cId); + $query->execute(); + } + + /** + * 查詢一個班級資料 + * + * @return array 班級資料陣列,格式為: + * + * array( 'class_id' => <班級ID>, + * 'name' => <班級顯示名稱>, + * 'memo' => <備註>, + * 'build_time' => <建立時間> + * ); + * + */ + public function queryClassGroup($cId) { + + $sqlString = "SELECT * FROM ".$this->table('CGroup'). + " WHERE `CID` = :cid"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':cid', $cId); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + $thisResult = $queryResultAll[0]; + // 製作回傳結果陣列 + $result = array('class_id' => $thisResult['CID'], + 'name' => $thisResult['CName'], + 'memo' => $thisResult['CMemo'], + 'build_time' => $thisResult['CBuild_Time'] + ); + return $result; + } + // 若都沒查到的話 + else { + return null; + } + } + + /** + * 查詢所有的班級資料 + * + * @return array 班級資料陣列,格式為: + * + * array( + * array( + * 'class_id' => <班級ID>, + * 'name' => <班級顯示名稱>, + * 'memo' => <備註>, + * 'build_time' => <建立時間> + * ) + * ); + * + */ + public function queryAllClassGroup() { + + $sqlString = "SELECT * FROM ".$this->table('CGroup'); + + $query = $this->connDB->prepare($sqlString); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + // 製作回傳結果陣列 + $result = array(); + foreach($queryResultAll as $key => $thisResult) { + array_push($result, + array( 'class_id' => $thisResult['CID'], + 'name' => $thisResult['CName'], + 'memo' => $thisResult['CMemo'], + 'build_time' => $thisResult['CBuild_Time']) + ); + } + return $result; + } + // 若都沒查到的話 + else { + return null; + } + } + + /** + * 修改一個群組的資料內容 + * + * 範例: + * + * $db = new Database\DBUser(); + * $db->changeClassGroupData(2, 'name', '五年一班'); + * + * @param string $cId 班級ID + * @param string $field 欄位名稱 + * @param string $value 內容 + */ + public function changeClassGroupData($cId, $field, $value) { + + $sqlField = null; + switch($field) { + case 'class_id': $sqlField = 'CID'; break; + case 'name': $sqlField = 'CName'; break; + case 'memo': $sqlField = 'CMemo'; break; + default: $sqlField = $field; break; + } + + + $sqlString = "UPDATE ".$this->table('CGroup'). + " SET `".$sqlField."` = :value". + " WHERE `CID` = :cid"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':cid', $cId); + $query->bindParam(':value', $value); + $query->execute(); + } + + /** + * 設定自動編號的起始值 + * @param int $num 自動編號起始值 + */ + public function setClassGroupIDAutoIncrement($num) { + + // TODO: 不帶值的話,以最後編號為起頭 + $sqlString = "ALTER TABLE ".$this->table('CGroup'). + " AUTO_INCREMENT = $num"; + + $this->connDB->exec($sqlString); + } } \ No newline at end of file diff --git a/htdocs/lib/User/ClassGroup.php b/htdocs/lib/User/ClassGroup.php index 46830d9..52aaf56 100644 --- a/htdocs/lib/User/ClassGroup.php +++ b/htdocs/lib/User/ClassGroup.php @@ -1,7 +1,167 @@ getName(); + * $group->setName('測試用'); + * echo $group->getName(); + * } + * catch (User\Exception\ClassNoFoundException $e) { + * echo 'No Found class: '. $e->getGroupId(); + * } + * + * @version 2.0.0 + * @package UElearning + * @subpackage User + */ +class ClassGroup { + + /** + * 群組ID + * @type int + */ + protected $cId; + + // ======================================================================== + + /** + * 查詢到此帳號的所有資訊的結果 + * + * 由 $this->getQuery() 抓取資料表中所有資訊,並放在此陣列裡 + * + * @type array + */ + protected $queryResultArray; + + /** + * 從資料庫取得此群組查詢 + * + * @throw UElearning\User\Exception\ClassNoFoundException + * @since 2.0.0 + */ + protected function getQuery(){ + + // 從資料庫查詢群組 + $db = new Database\DBUser(); + $groupInfo = $db->queryClassGroup($this->cId); + + // 判斷有沒有這個群組 + if( $groupInfo != null ) { + $this->queryResultArray = $groupInfo; + } + else throw new Exception\ClassNoFoundException($this->cId); + } + + /** + * 從資料庫更新此群組設定 + * + * @since 2.0.0 + */ + protected function setUpdate($field, $value){ + + // 將新設定寫進資料庫裡 + $db = new Database\DBUser(); + $db->changeClassGroupData($this->cId, $field, $value); + $this->getQuery(); + } + + // ======================================================================== + + /** + * 建構子 + * + * @param int $inputCID 班級ID + * @since 2.0.0 + */ + public function __construct($inputCID){ + $this->cId = $inputCID; + $this->getQuery(); + } + + // ======================================================================== + + /** + * 取得群組ID + * + * @return int 班級ID + * @since 2.0.0 + */ + public function getID(){ + return $this->cId; + } + + // ------------------------------------------------------------------------ + + /** + * 取得帳號建立時間 + * + * @return string 建立時間 + * @since 2.0.0 + */ + public function getCreateTime(){ + return $this->queryResultArray['build_time']; + } + // ======================================================================== + + /** + * 取得群組顯示名稱 + * + * @return string 群組名稱 + * @since 2.0.0 + */ + public function getName(){ + return $this->queryResultArray['name']; + } + + /** + * 設定群組顯示名稱 + * + * @param string $name 群組名稱 + * @since 2.0.0 + */ + public function setName($name){ + $this->setUpdate('name', $name); + } + + /** + * 取得帳號備註資訊 + * + * @return string 使用者帳號備註資訊 + * @since 2.0.0 + */ + public function getMemo(){ + return $this->queryResultArray['memo']; + } + + /** + * 修改帳號備註資訊 + * + * @param string $input 新的帳號備註資訊 + * @since 2.0.0 + */ + public function setMemo($input){ + $this->setUpdate('memo', $input); + } + +} \ No newline at end of file diff --git a/htdocs/lib/User/ClassGroupAdmin.php b/htdocs/lib/User/ClassGroupAdmin.php index 2ba6220..fe472d5 100644 --- a/htdocs/lib/User/ClassGroupAdmin.php +++ b/htdocs/lib/User/ClassGroupAdmin.php @@ -4,4 +4,142 @@ */ namespace UElearning\User; -// TODO: write this code \ No newline at end of file + +require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; +require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Exception.php'; +use UElearning\Database; + +/** + * 管理班級群組的操作 + * + * @author Yuan Chiu + * @version 2.0.0 + * @package UElearning + * @subpackage User + */ +class ClassGroupAdmin { + + /** + * 建立班級 + * + * 建立班級群組範例: + * + * try { + * $groupAdmin = new User\ClassGroupAdmin(); + * $newId = null; + * $newId = $groupAdmin->create( + * array( 'name' => '學生', + * 'memo' => null + * )); + * echo '你剛建立:'.$newId; + * } + * // 若已有重複班級ID + * catch (User\Exception\ClassIdExistException $e) { + * echo 'Is exist class: ', $e->getGroupId(); + * } + * + * @param array $classGroupArray 班級群組資訊陣列,格式為: + * array( 'class_id' => 12, + * 'name' => '學生', + * 'memo' => null ) + * @return int 剛剛新增進去的ID + * @throw UElearning\User\Exception\ClassIdExistException + * @since 2.0.0 + */ + public function create($classGroupArray) { + + // 檢查有無填寫 + if(isset($classGroupArray)) { + + // 若此id已存在 + if( isset($classGroupArray['class_id']) && + $this->isExist($classGroupArray['class_id']) ) { + + throw new Exception\ClassIdExistException( + $classGroupArray['class_id'] ); + } + // 沒有問題 + else { + // 處理未帶入的資料 + if( !isset($classGroupArray['class_id']) ){ + $classGroupArray['class_id'] = null; + } + + // 處理未帶入的資料 + if( !isset($classGroupArray['name']) ){ + $classGroupArray['name'] = null; + } + // 處理未帶入的資料 + if( !isset($classGroupArray['memo']) ){ + $classGroupArray['memo'] = null; + } + + // 新增一筆使用者資料進資料庫 + $db = new Database\DBUser(); + $id = $db->insertClassGroup( + $classGroupArray['class_id'], + $classGroupArray['name'], + $classGroupArray['memo'] + ); + + // 回傳剛剛新增的ID + return $id; + } + } + else throw Exception\NoDataException(); + } + + /** + * 是否已有相同名稱的班級ID + * + * @param int $class_id 班級ID + * @return bool 已有相同的班級ID + * @since 2.0.0 + */ + public function isExist($class_id) { + + $db = new Database\DBUser(); + $info = $db->queryClassGroup($class_id); + + if( $info != null ) return true; + else return false; + } + + /** + * 移除此班級 + * + * 範例: + * + * try { + * $groupAdmin = new User\ClassGroupAdmin(); + * $groupAdmin->remove(2); + * + * } + * catch (User\Exception\ClassNoFoundException $e) { + * echo 'No Found class: ', $e->getGroupId(); + * } + * + * @param int $class_id 班級ID + * @throw UElearning\User\Exception\ClassNoFoundException + * @since 2.0.0 + */ + public function remove($class_id) { + + // 若有此使用者 + if($this->isExist($class_id)) { + + // TODO: 檢查所有關聯的資料,確認是否可以移除 + + // 移除資料庫中的使用者 + $db = new Database\DBUser(); + $db->deleteClassGroup($class_id); + } + // 若沒有這位使用者 + else { + throw new Exception\ClassNoFoundException($class_id); + } + + } + +} \ No newline at end of file diff --git a/htdocs/lib/User/Exception.php b/htdocs/lib/User/Exception.php index f9a294a..1359a91 100644 --- a/htdocs/lib/User/Exception.php +++ b/htdocs/lib/User/Exception.php @@ -42,6 +42,8 @@ abstract class UserException extends \UnexpectedValueException { /** * 沒有找到此帳號 * @since 2.0.0 + * @package UElearning + * @subpackage User */ class UserNoFoundException extends UserException { /** @@ -56,6 +58,8 @@ class UserNoFoundException extends UserException { /** * 使用者登入密碼錯誤 * @since 2.0.0 + * @package UElearning + * @subpackage User */ class UserPasswordErrException extends UserException { /** @@ -70,6 +74,8 @@ class UserPasswordErrException extends UserException { /** * 此帳號未啟用 * @since 2.0.0 + * @package UElearning + * @subpackage User */ class UserNoActivatedException extends UserException { /** @@ -85,6 +91,8 @@ class UserNoActivatedException extends UserException { /** * 已有重複的使用者名稱 * @since 2.0.0 + * @package UElearning + * @subpackage User */ class UserIdExistException extends UserException { /** @@ -134,6 +142,8 @@ abstract class GroupException extends \UnexpectedValueException { /** * 已有重複的使用者群組ID * @since 2.0.0 + * @package UElearning + * @subpackage User */ class GroupIdExistException extends GroupException { /** @@ -148,6 +158,8 @@ class GroupIdExistException extends GroupException { /** * 沒有找到此使用者群組ID * @since 2.0.0 + * @package UElearning + * @subpackage User */ class GroupNoFoundException extends GroupException { /** @@ -162,7 +174,41 @@ class GroupNoFoundException extends GroupException { // ============================================================================ /** - * 使用者群組例外 + * 已有重複的使用者群組ID + * @since 2.0.0 + * @package UElearning + * @subpackage User + */ +class ClassIdExistException extends GroupException { + /** + * 已有重複的使用者名稱 + * @param string $groupId 輸入的使用者群組ID + */ + public function __construct($groupId) { + parent::__construct($groupId, 'ClassId: "'.$groupId.'" is exist.'); + } +} + +/** + * 沒有找到此使用者群組ID + * @since 2.0.0 + * @package UElearning + * @subpackage User + */ +class ClassNoFoundException extends GroupException { + /** + * 沒有找到此帳號 + * @param string $groupId 輸入的使用者群組ID + */ + public function __construct($groupId) { + parent::__construct($groupId, 'Class Group: "'.$groupId.'" is no found.'); + } +} + +// ============================================================================ + +/** + * 沒有此權限例外 * @since 2.0.0 * @package UElearning * @subpackage User diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php index 3b63e94..47955b7 100644 --- a/htdocs/lib/User/User.php +++ b/htdocs/lib/User/User.php @@ -276,8 +276,7 @@ class User { * @since 2.0.0 */ public function isEnable(){ - if($this->queryResultArray['enable'] == 0) return false; - else return true; + return $this->queryResultArray['enable']; } /** diff --git a/htdocs/lib/User/UserGroupAdmin.php b/htdocs/lib/User/UserGroupAdmin.php index 09ed50a..c443c39 100644 --- a/htdocs/lib/User/UserGroupAdmin.php +++ b/htdocs/lib/User/UserGroupAdmin.php @@ -23,7 +23,7 @@ class UserGroupAdmin { /** * 建立群組 * - * 建立使用者範例: + * 建立使用者群組範例: * * try { * $groupAdmin = new User\UserGroupAdmin(); @@ -36,12 +36,12 @@ class UserGroupAdmin { * )); * * } - * // 若已有重複帳號名稱 + * // 若已有重複群組ID * catch (User\Exception\GroupIdExistException $e) { * echo 'Is exist group: ', $e->getGroupId(); * } * - * @param array $groupArray 使用者資訊陣列,格式為: + * @param array $groupArray 使用者群組資訊陣列,格式為: * array( 'group_id' => 'student', * 'name' => '學生', * 'memo' => null, // (optional) 預設為null diff --git a/tests/Database/DBUserTest.php b/tests/Database/DBUserTest.php index 23b35ed..66eee31 100644 --- a/tests/Database/DBUserTest.php +++ b/tests/Database/DBUserTest.php @@ -129,7 +129,7 @@ class DBUserTest extends \PHPUnit_Framework_TestCase 'harf-line-learn', 1, '元兒~', 'Yuan Chiu', 'chyuaner@gmail.com', null), - array('eee_unittest', 'qqqssss', 'admin', null, 1, + array('eee_unittest', 'qqqssss', 'admin', null, 0, 'harf-line-learn', '1', 'sss', 'Yuan Chiu', 'chyuanesr@gmail.com', null) ); @@ -205,8 +205,12 @@ class DBUserTest extends \PHPUnit_Framework_TestCase */ public function groupDataProvider(){ return array( - array('testG_a', '測試用群組a', null, '1', '0'), - array('testG_b', '測試用群組b', 'testhahaha Groups', '0', '1') + array('testG_a', '測試用群組a', null, 1, 0), + array('testG_b', '測試用群組b', 'testhahaha Groups', 0, 1) ); } + + // ======================================================================== + + // TODO: ClassGroup Test } \ No newline at end of file diff --git a/tests/User/ClassGroupAdminTest.php.bak b/tests/User/ClassGroupAdminTest.php.bak new file mode 100644 index 0000000..23daa9e --- /dev/null +++ b/tests/User/ClassGroupAdminTest.php.bak @@ -0,0 +1,92 @@ + + */ +namespace UElearning; + +require_once UELEARNING_LIB_ROOT.'/User/ClassGroupAdmin.php'; +use UElearning\User\ClassGroupAdmin; + +class ClassGroupAdminTest extends \PHPUnit_Framework_TestCase +{ + + protected $classId; + + protected function setUp(){ + $this->classId = array(); + } + + /** + * 測試建立群組 + * + * @dataProvider groupDataProvider + */ + public function testCreateGroup($cId, $name, $memo){ + + try { + $groupAdmin = new User\ClassGroupAdmin(); + $newId = null; + $newId = $groupAdmin->create( + array( 'class_id' => $cId, + 'name' => $name, + 'memo' => $memo + )); + + array_push($this->classId, $newId); + print_r($this->classId); + } + // 若已有重複帳號名稱 + catch (User\Exception\ClassIdExistException $e) { + throw $e; + } + + } + + /** + * 測試查詢群組 + * + * @dataProvider groupDataProvider + */ + public function testCheckExist($cId){ + + if(isset($cid)) { + $groupAdmin = new User\ClassGroupAdmin(); + // 比對資料是否吻合 + $this->assertEquals($groupAdmin->isExist($cId), true); + } + } + + /** + * 測試移除使用者 + * @depends testCreateGroup + */ + public function testDeleteGroup() { + print_r($this->classId); + foreach($this->classId as $thisId) { + + try { + $groupAdmin = new User\ClassGroupAdmin(); + $groupAdmin->remove($thisId); + + $this->assertEquals($groupAdmin->isExist($thisId), false); + } + catch (User\Exception\ClassNoFoundException $e) { + throw $e; + } + } + } + + /** + * 測試時要填的資料 + */ + public function groupDataProvider(){ + return array( + array(null, '測試用群組a', null), + array(2859, '測試用群組b', 'testhahaha Groups') + ); + } + +} \ No newline at end of file From adf9c28135780d83907fab7dc5fe7bb2d571e864 Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Thu, 9 Oct 2014 03:28:57 +0800 Subject: [PATCH 34/35] Add UserSession Class --- htdocs/lib/Database/DBUserSession.php | 210 ++++++++++++++++++++++++++ htdocs/lib/User/Exception.php | 35 +++++ htdocs/lib/User/UserSession.php | 187 ++++++++++++++++++++--- 3 files changed, 414 insertions(+), 18 deletions(-) create mode 100644 htdocs/lib/Database/DBUserSession.php diff --git a/htdocs/lib/Database/DBUserSession.php b/htdocs/lib/Database/DBUserSession.php new file mode 100644 index 0000000..48d85a3 --- /dev/null +++ b/htdocs/lib/Database/DBUserSession.php @@ -0,0 +1,210 @@ + + * @version 2.0.0 + * @package UElearning + * @subpackage Database + */ +class DBUserSession extends Database { + + /** + * 新增登入資料 + * @param string $token 登入token + * @param string $uId 帳號ID + * @param string $agent 登入所使用的裝置 + */ + public function login($token, $uId, $agent) { + + //紀錄登入階段進資料庫 + $sqlString = "INSERT INTO ".$this->table('UserSession'). + " (`UsID`, `UToken`, `UID`, `UAgent`, `ULoginDate`, `ULogoutDate`) + VALUES (NULL , :token, :uid , :agent , NOW() , NULL)"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":token", $token); + $query->bindParam(":uid", $uId); + $query->bindParam(":agent", $agent); + $query->execute(); + } + + /** + * 標注此登入階段為登出 + * @param string $token 登入token + */ + public function logout($token) { + + $sqlString = "UPDATE ".$this->table('UserSession'). + " SET `UToken` = NULL, `ULogoutDate` = NOW() + WHERE `UToken` = :token"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":token", $token); + $query->execute(); + } + + /** + * 標注此帳號所有的登入階段為登出 + * @param string $uid 帳號ID + * @return int 修改幾筆資料 + */ + public function logoutByUserId($uid) { + + $sqlString = "UPDATE ".$this->table('UserSession'). + " SET `UToken` = NULL, `ULogoutDate` = NOW() + WHERE `UID` = :uid AND `UToken` IS NOT NULL"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(":uid", $uid); + $query->execute(); + return $query->rowCount(); + } + + /** + * 以token查詢 + * @param string $token 登入token + * @return array 登入階段資料陣列,格式為: + * array( + * 'session_id' => <登入編號>, + * 'token' => <登入Token>, + * 'user_id' => <使用者>, + * 'agent' => <用哪個裝置登入>, + * 'login_date' => <登入時間>, + * 'logout_date' => <登出時間> + * ); + */ + public function queryByToken($token) { + $sqlString = "SELECT * FROM ".$this->table('UserSession'). + " WHERE `UToken` = :token"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':token', $token); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + $queryResult = $queryResultAll[0]; + + $result = array( + 'session_id' => $queryResult['UsID'], + 'token' => $queryResult['UToken'], + 'user_id' => $queryResult['UID'], + 'agent' => $queryResult['UAgent'], + 'login_date' => $queryResult['ULoginDate'], + 'logout_date' => $queryResult['ULogoutDate'] + ); + + return $result; + } + else return null; + } + + /** + * 以使用者ID查詢 + * @param string $uId 使用者ID + * @return array 登入階段資料陣列,格式為: + * array( + * array( + * 'session_id' => <登入編號>, + * 'token' => <登入Token>, + * 'user_id' => <使用者>, + * 'agent' => <用哪個裝置登入>, + * 'login_date' => <登入時間>, + * 'logout_date' => <登出時間> + * ) + * ); + */ + public function queryByUserId($uId) { + $sqlString = "SELECT * FROM ".$this->table('UserSession'). + " WHERE `UID` = :uid"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':uid', $uId); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + + // 製作回傳結果陣列 + $result = array(); + foreach($queryResultAll as $key => $thisResult) { + array_push($result, + array( + 'session_id' => $thisResult['UsID'], + 'token' => $thisResult['UToken'], + 'user_id' => $thisResult['UID'], + 'agent' => $thisResult['UAgent'], + 'login_date' => $thisResult['ULoginDate'], + 'logout_date' => $thisResult['ULogoutDate'] + ) + ); + } + return $result; + } + else return null; + } + + /** + * 以使用者ID查詢,目前所有已登入的登入階段 + * @param string $uId 使用者ID + * @return array 登入階段資料陣列,格式為: + * array( + * array( + * 'session_id' => <登入編號>, + * 'token' => <登入Token>, + * 'user_id' => <使用者>, + * 'agent' => <用哪個裝置登入>, + * 'login_date' => <登入時間>, + * 'logout_date' => <登出時間> + * ) + * ); + */ + public function queryLoginByUserId($uId) { + $sqlString = "SELECT * FROM ".$this->table('UserSession'). + " WHERE `UID` = :uid AND `UToken` IS NOT NULL"; + + $query = $this->connDB->prepare($sqlString); + $query->bindParam(':uid', $uId); + $query->execute(); + + $queryResultAll = $query->fetchAll(); + // 如果有查到一筆以上 + if( count($queryResultAll) >= 1 ) { + + // 製作回傳結果陣列 + $result = array(); + foreach($queryResultAll as $key => $thisResult) { + array_push($result, + array( + 'session_id' => $thisResult['UsID'], + 'token' => $thisResult['UToken'], + 'user_id' => $thisResult['UID'], + 'agent' => $thisResult['UAgent'], + 'login_date' => $thisResult['ULoginDate'], + 'logout_date' => $thisResult['ULogoutDate'] + ) + ); + } + return $result; + } + else return null; + } + +} \ No newline at end of file diff --git a/htdocs/lib/User/Exception.php b/htdocs/lib/User/Exception.php index 1359a91..f24ae2e 100644 --- a/htdocs/lib/User/Exception.php +++ b/htdocs/lib/User/Exception.php @@ -238,4 +238,39 @@ class PermissionNoFoundException extends \UnexpectedValueException { public function getName() { return $this->permissionName; } + +} + +// ============================================================================ + +/** + * 找不到此登入階段 + * @since 2.0.0 + * @package UElearning + * @subpackage User + */ +class LoginTokenNoFoundException extends \UnexpectedValueException { + + /** + * 登入階段Token + * @type string + */ + private $token; + + /** + * 找不到此登入階段例外 + * @param string $token 登入階段Token + */ + public function __construct($token) { + $this->token = $token; + parent::__construct('No Found Login Token: '.$this->token); + } + + /** + * 取得輸入的登入階段Token + * @return string 登入階段Token + */ + public function getToken() { + return $this->token; + } } \ No newline at end of file diff --git a/htdocs/lib/User/UserSession.php b/htdocs/lib/User/UserSession.php index 0f66d39..f2f5b46 100644 --- a/htdocs/lib/User/UserSession.php +++ b/htdocs/lib/User/UserSession.php @@ -5,6 +5,13 @@ namespace UElearning\User; +require_once UELEARNING_LIB_ROOT.'/User/User.php'; +require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; +require_once UELEARNING_LIB_ROOT.'/Util/Password.php'; +require_once UELEARNING_LIB_ROOT.'/Database/DBUserSession.php'; +use UElearning\Util; +use UElearning\Database; + /** * 使用者登入階段管理 * @@ -17,45 +24,166 @@ class UserSession { /** * 使用者登入 - * @param string $userId 帳號名稱 - * @param string $password 密碼 - * @return string 登入session token - * @since 2.0.0 + * + * 範例: + * + * try { + * $session = new User\UserSession(); + * echo 'Token: '$session->login('yuan', '123456', 'browser'); + * } + * catch (User\Exception\UserNoFoundException $e) { + * echo 'No Found user: '. $e->getUserId(); + * } + * catch (User\Exception\UserPasswordErrException $e) { + * echo 'User Password wrong: '. $e->getUserId(); + * } + * catch (User\Exception\UserNoActivatedException $e) { + * echo 'User No Activiated: '. $e->getUserId(); + * } + * + * @param string $userId 帳號名稱 + * @param string $password 密碼 + * @param string $agent 用什麼裝置登入 + * @return string 登入session token + * @throw UElearning\User\Exception\UserNoFoundException + * @throw UElearning\User\Exception\UserPasswordErrException + * @throw UElearning\User\Exception\UserNoActivatedException + * @since 2.0.0 */ - public function login($userId, $password) { - // TODO: Fill code in - // 如果登入錯誤,就丟例外 + public function login($userId, $password, $agent) { + + try { + $user = new User($userId); + + // 登入密碼錯誤的話 + if( !$user->isPasswordCorrect($password) ) { + throw new Exception\UserPasswordErrException($userId); + } + // 此帳號已被停用 + else if( !$user->isEnable() ) { + throw new Exception\UserNoActivatedException($userId); + } + // 沒問題,登入此帳號 + else { + + // 使用資料庫 + $db = new Database\DBUserSession(); + + // 產生登入token + $passUtil = new Util\Password(); + $token = null; + // 防止產生出重複的token + do { + $token = $passUtil->generator(32); + } + while ($db->queryByToken($token)); + + // 登入資訊寫入資料庫 + $db->login($token, $userId, $agent); + + return $token; + } + } + // 沒有找到使用者 + catch (User\Exception\UserNoFoundException $e) { + echo 'No Found user: '. $e->getUserId(); + } } // ======================================================================== /** * 使用者登出 + * + * 範例: + * + * try { + * $session = new User\UserSession(); + * $session->logout('YdcfzqUuuRAR]4h6u4^Ew-qa4A-kvD5C'); + * } + * catch (User\Exception\LoginTokenNoFoundException $e) { + * echo 'No Login by token: '. $e->getToken(); + * } + * * @param string $token 登入階段token + * @throw \UElearning\User\Exception\LoginTokenNoFoundException * @since 2.0.0 */ public function logout($token) { - // TODO: Fill code in + + $db = new Database\DBUserSession(); + + // 如果有找到此登入階段 + if( $db->queryByToken($token) ) { + $db->logout($token); + } + // 沒有此登入階段 + else { + throw new Exception\LoginTokenNoFoundException($token); + } } /** * 將其他已登入的裝置登出 * @param string $token 登入階段token + * @return int 已登出數量 + * @throw \UElearning\User\Exception\LoginTokenNoFoundException * @since 2.0.0 */ public function logoutOtherSession($token) { - // TODO: Fill code in + + // 先從token查詢到使用者是誰 + $user_id = $this->getUserId($token); + + $db = new Database\DBUserSession(); + // 如果有找到此登入階段 + if( $db->queryByToken($token) ) { + // 查詢者個使用者的所有登入階段 + $allSession = $db->queryLoginByUserId($user_id); + + // 紀錄已登出數量 + $logoutTotal = 0; + if(isset($allSession)) { + // 將所有非此Token的裝置登出 + foreach($allSession as $key=>$thisSession) { + if($thisSession['token'] != $token) { + $this->logout($thisSession['token']); + $logoutTotal++; + } + } + }; + return $logoutTotal; + } + // 沒有此登入階段 + else { + throw new Exception\LoginTokenNoFoundException($token); + } } - /** * 取得使用者物件 * @param string $token 登入階段token * @return User 使用者物件 + * @throw \UElearning\User\Exception\LoginTokenNoFoundException * @since 2.0.0 */ public function getUser($token) { - // TODO: Fill code in + $userId = $this->getUserId($token); + return new User($userId); + } + + /** + * 取得使用者ID + * @param string $token 登入階段token + * @return string 使用者ID + * @throw \UElearning\User\Exception\LoginTokenNoFoundException + * @since 2.0.0 + */ + public function getUserId($token) { + $db = new Database\DBUserSession(); + $sessionArray = $db->queryByToken($token); + if(isset($sessionArray)) return $sessionArray['user_id']; + else throw new Exception\LoginTokenNoFoundException($token); } /** @@ -65,7 +193,7 @@ class UserSession { * @since 2.0.0 */ public function getTokenInfo($token) { - // TODO: Fill code in + // TODO: 取得登入資訊 } // ======================================================================== @@ -77,7 +205,7 @@ class UserSession { * @since 2.0.0 */ public function getUserLoginInfo($userId) { - // TODO: Fill code in + // TODO: 取得所有此使用者已登入的登入階段資訊 } /** @@ -86,8 +214,20 @@ class UserSession { * @return int 所有以登入的數量 * @since 2.0.0 */ - public function getUserLoginTotal($userId) { - // TODO: Fill code in + public function getLoginTotalByUserId($userId) { + + // 確保若無此使用者則丟例外 + $user = new User($userId); + + // 查詢者個使用者的所有登入階段 + $db = new Database\DBUserSession(); + $allSession = $db->queryLoginByUserId($userId); + + // 回傳目前已登入的裝置數 + if(isset($allSession)) { + return count($allSession); + } + else return 0; } /** @@ -99,15 +239,26 @@ class UserSession { * @since 2.0.0 */ public function getUserAllInfo($userId) { - // TODO: Fill code in + // TODO: 取得所有此使用者全部的登入階段資訊 } /** * 將此使用者全部登入階段登出 * @param string $userId 使用者帳號名稱 + * @return int 已登出數量 + * @throw UElearning\User\Exception\UserNoFoundException * @since 2.0.0 */ - public function logoutUserAllSession($userId) { - // TODO: Fill code in + public function logoutByUser($userId) { + + // 確保若無此使用者則丟例外 + $user = new User($userId); + + // 登出此使用者所有登入階段 + $db = new Database\DBUserSession(); + + $logoutTotal = 0; + $logoutTotal = $db->logoutByUserId($userId); + return $logoutTotal; } } \ No newline at end of file From 697e213aa384b483ec6ecbd84b00e1596d734b1c Mon Sep 17 00:00:00 2001 From: Yuan Chiu Date: Sun, 12 Oct 2014 17:00:54 +0800 Subject: [PATCH 35/35] User Manager to fix & fill setclass --- htdocs/lib/User/User.php | 59 +++++++++++++++++++++++++++++---- htdocs/lib/User/UserAdmin.php | 10 ++++-- htdocs/lib/User/UserSession.php | 26 ++++++++++++++- 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/htdocs/lib/User/User.php b/htdocs/lib/User/User.php index 47955b7..c459e01 100644 --- a/htdocs/lib/User/User.php +++ b/htdocs/lib/User/User.php @@ -8,6 +8,8 @@ namespace UElearning\User; require_once UELEARNING_LIB_ROOT.'/Database/DBUser.php'; require_once UELEARNING_LIB_ROOT.'/User/UserGroupAdmin.php'; require_once UELEARNING_LIB_ROOT.'/User/UserGroup.php'; +require_once UELEARNING_LIB_ROOT.'/User/ClassGroupAdmin.php'; +require_once UELEARNING_LIB_ROOT.'/User/ClassGroup.php'; require_once UELEARNING_LIB_ROOT.'/User/Exception.php'; require_once UELEARNING_LIB_ROOT.'/Exception.php'; require_once UELEARNING_LIB_ROOT.'/Util/Password.php'; @@ -232,7 +234,6 @@ class User { else { throw new Exception\GroupNoFoundException($toGroup); } - } // ------------------------------------------------------------------------ @@ -248,23 +249,69 @@ class User { } /** - * 取得所在群組顯示名稱 + * 取得所在班級名稱 * * @return string 班級名稱 * @since 2.0.0 */ public function getClassName(){ // TODO: 取得所在群組顯示名稱 + // 群組ID + $classID = $this->queryResultArray['class_id']; + + // 檢查有此群組 + if(isset($classID)) { + // 取得群組名稱 + try { + $group = new ClassGroup($classID); + return $group->getName(); + } + catch (Exception\ClassNoFoundException $e) { + throw $e; + } + } + else return null; } /** - * 設定所在群組 - * - * @param string $toGroup 班級ID + * 設定所在班級 + * + * 範例: + * + * try { + * $user = new User\User('yuan'); + * + * try { + * $user->setClass(1); + * } + * catch (User\Exception\ClassNoFoundException $e) { + * echo 'No Class to set: '. $e->getGroupId(); + * } + * } + * catch (User\Exception\UserNoFoundException $e) { + * echo 'No Found user: '. $e->getUserId(); + * } + * + * @param string $toClass 班級ID * @since 2.0.0 */ public function setClass($toClass){ - // TODO: 設定所在群組 + + // 檢查有此群組 + if(isset($toClass)) { + + $classGroupAdmin = new ClassGroupAdmin(); + if($classGroupAdmin->isExist($toClass)) { + $this->setUpdate('class_id', $toClass); + } + else { + throw new Exception\ClassNoFoundException($toGroup); + } + } + else { + $this->setUpdate('class_id', null); + } + } // ======================================================================== diff --git a/htdocs/lib/User/UserAdmin.php b/htdocs/lib/User/UserAdmin.php index 5df69f9..1605ac7 100644 --- a/htdocs/lib/User/UserAdmin.php +++ b/htdocs/lib/User/UserAdmin.php @@ -26,6 +26,10 @@ class UserAdmin { * 建立使用者 * * 建立使用者範例: + * + * require_once __DIR__.'/../config.php'; + * require_once UELEARNING_LIB_ROOT.'/User/UserAdmin.php'; + * use UElearning\User; * * try { * $userAdmin = new User\UserAdmin(); @@ -35,13 +39,13 @@ class UserAdmin { * 'group_id' => 'admin', * 'enable' => true, * 'nickname' => '艾瑞克', - * 'email' => 'eric@example.com' - * )); + * 'email' => 'eric@example.com' ) + * ); * * } * // 若已有重複帳號名稱 * catch (User\Exception\UserIdExistException $e) { - * echo 'Is exist user: ', $e->getUserId(); + * echo 'Is exist user: ', $e->getUserId(); * } * * @param array $userInfoArray 使用者資訊陣列,格式為: diff --git a/htdocs/lib/User/UserSession.php b/htdocs/lib/User/UserSession.php index f2f5b46..d4481f6 100644 --- a/htdocs/lib/User/UserSession.php +++ b/htdocs/lib/User/UserSession.php @@ -27,9 +27,14 @@ class UserSession { * * 範例: * + * require_once __DIR__.'/../config.php'; + * require_once UELEARNING_LIB_ROOT.'/User/UserSession.php'; + * use UElearning\User; + * * try { * $session = new User\UserSession(); - * echo 'Token: '$session->login('yuan', '123456', 'browser'); + * $loginToken = $session->login('yuan', 'password', 'browser'); + * echo 'Token: '.$loginToken; * } * catch (User\Exception\UserNoFoundException $e) { * echo 'No Found user: '. $e->getUserId(); @@ -162,6 +167,25 @@ class UserSession { /** * 取得使用者物件 + * + * 範例: + * + * try { + * // 正常寫法 + * $userSession = new User\UserSession(); + * $user = $userSession->getUser(‘YZ8@(3fYb[!f!A^E4^6b4LuqxSXgZ2FJ’); + * + * // 簡短寫法(PHP 5.4以上才支援) + * //$user = (new User\UserSession())->getUser('YZ8@(3fYb[!f!A^E4^6b4LuqxSXgZ2FJ'); + * + * // 撈帳號資料 + * echo '暱稱: '.$user->getNickName(); // 取得暱稱 + * echo '本名: '.$user->getRealName(); // 取得本名 + * } + * catch (User\Exception\LoginTokenNoFoundException $e) { + * echo 'No Found Token: '. $e->getToken(); + * } + * * @param string $token 登入階段token * @return User 使用者物件 * @throw \UElearning\User\Exception\LoginTokenNoFoundException