From e515ebe8290056da39cda332be501de5370dcc6a Mon Sep 17 00:00:00 2001 From: Sean Goresht Date: Mon, 31 Dec 2012 02:48:52 -0700 Subject: [PATCH] Revamped layout to HTML5 and CSS3 RokMongo goes responsive! Enjoy this new sexy login screen using the greatest HTML5 techniques. Warning: I broke some stuff while working on the main page, so this is only developer-ready so far. --- .idea/.name | 1 + .idea/cssxfire.xml | 9 + .idea/encodings.xml | 5 + .idea/libraries/sass_stdlib.xml | 8 + .idea/misc.xml | 8 + .idea/modules.xml | 9 + .idea/rockmongo.iml | 9 + .idea/scopes/scope_settings.xml | 5 + .idea/vcs.xml | 7 + .idea/workspace.xml | 791 +++++++ app/classes/BaseController.php | 225 +- app/classes/Services_JSON.php | 1538 ++++++------ app/classes/VarEval.php | 101 +- app/classes/VarExportor.php | 202 +- app/configs/rplugin.php | 11 +- app/controllers/admin.php | 202 +- app/controllers/collection.php | 726 +++--- app/controllers/db.php | 1062 +++++---- app/controllers/field.php | 329 +-- app/controllers/index.php | 6 +- app/controllers/login.php | 125 +- app/controllers/logout.php | 35 +- app/controllers/server.php | 590 ++--- app/funcs/functions.php | 371 +-- app/funcs/render.php | 420 ++-- app/funcs/rock.php | 152 +- app/langs/de_de/message.php | 6 +- app/langs/en_us/message.php | 6 +- app/langs/es_es/message.php | 6 +- app/langs/fr_fr/message.php | 2 +- app/langs/it_it/message.php | 6 +- app/langs/ja_jp/message.php | 140 +- app/langs/pt_br/message.php | 2 +- app/langs/pt_pt/message.php | 140 +- app/langs/ru_ru/message.php | 420 ++-- app/langs/zh_cn/message.php | 160 +- app/langs/zh_tw/message.php | 160 +- app/lib/core/REvent.php | 171 +- app/lib/core/RFilter.php | 184 +- app/lib/core/RPlugin.php | 216 +- app/lib/ext/RExtController.php | 37 +- app/lib/mime/types.php | 187 +- app/lib/mongo/RMongo.php | 231 +- app/lib/mongo/RMongoException.php | 5 +- app/lib/mongo/RObject.php | 710 +++--- app/lib/mongo/RQuery.php | 1319 ++++++----- app/lib/mongo/mongo.php | 656 ++++++ app/lib/page/RPage.php | 1060 +++++---- app/lib/page/RPageStyle1.php | 69 +- app/lib/page/lang/de_de.php | 2 +- app/lib/page/lang/default.php | 32 +- app/lib/page/lang/en.php | 32 +- app/lib/page/lang/en_us.php | 32 +- app/lib/page/lang/es_es.php | 2 +- app/lib/page/lang/ru_ru.php | 34 +- app/lib/page/lang/zh.php | 32 +- app/lib/page/lang/zh_cn.php | 32 +- app/models/MCollection.php | 63 +- app/models/MDb.php | 64 +- app/models/MMongo.php | 90 +- app/models/MServer.php | 889 +++---- app/models/MUser.php | 264 ++- config.php | 42 +- index.php | 18 +- js/jquery-1.4.2.min.js | 154 -- js/jquery-1.8.2.min.js | 2 + rock.php | 480 ++-- themes/default/css/base.css | 0 themes/default/css/collection.css | 62 +- themes/default/css/global.css | 239 +- themes/default/css/grids.css | 1 + .../css/jquery-ui-1.8.4.smoothness.css | 2056 ++++++++++++++--- themes/default/css/layout-default-1.3.0.css | 297 +-- themes/default/css/mixins.css | 1 + themes/default/css/style.css | 1 + themes/default/css/variables.css | 0 .../_appearance.scssc | Bin 0 -> 2263 bytes .../_background-clip.scssc | Bin 0 -> 4062 bytes .../_background-origin.scssc | Bin 0 -> 4263 bytes .../_background-size.scssc | Bin 0 -> 3487 bytes .../_border-radius.scssc | Bin 0 -> 12218 bytes .../_box-shadow.scssc | Bin 0 -> 10401 bytes .../_box-sizing.scssc | Bin 0 -> 1383 bytes .../_box.scssc | Bin 0 -> 9757 bytes .../_columns.scssc | Bin 0 -> 13002 bytes .../_filter.scssc | Bin 0 -> 2623 bytes .../_font-face.scssc | Bin 0 -> 5061 bytes .../_hyphenation.scssc | Bin 0 -> 6082 bytes .../_images.scssc | Bin 0 -> 34719 bytes .../_inline-block.scssc | Bin 0 -> 2919 bytes .../_opacity.scssc | Bin 0 -> 2761 bytes .../_regions.scssc | Bin 0 -> 2663 bytes .../_shared.scssc | Bin 0 -> 9786 bytes .../_text-shadow.scssc | Bin 0 -> 12443 bytes .../_transform.scssc | Bin 0 -> 63064 bytes .../_transition.scssc | Bin 0 -> 32814 bytes .../_hacks.scssc | Bin 0 -> 5927 bytes .../_css3.scssc | Bin 0 -> 1422 bytes .../_reset.scssc | Bin 0 -> 367 bytes .../_support.scssc | Bin 0 -> 5480 bytes .../_utilities.scssc | Bin 0 -> 24704 bytes .../base.scssc | Bin 0 -> 133 bytes .../grids.scssc | Bin 0 -> 15045 bytes .../mixins.scssc | Bin 0 -> 632 bytes .../style.scssc | Bin 0 -> 8936 bytes .../variables.scssc | Bin 0 -> 3609 bytes themes/default/sass/base.scss | 0 themes/default/sass/grids.scss | 147 ++ themes/default/sass/mixins.scss | 3 + themes/default/sass/style.scss | 74 + themes/default/sass/variables.scss | 31 + themes/default/views/admin/dbs.php | 169 +- themes/default/views/admin/index.php | 170 +- themes/default/views/admin/top.php | 25 +- .../views/collection/collectionDuplicate.php | 44 +- .../views/collection/collectionIndexes.php | 39 +- .../views/collection/collectionProps.php | 40 +- .../views/collection/collectionRename.php | 50 +- .../views/collection/collectionStats.php | 50 +- .../views/collection/collectionValidate.php | 8 +- .../default/views/collection/createIndex.php | 125 +- themes/default/views/collection/createRow.php | 64 +- .../default/views/collection/explainQuery.php | 16 +- themes/default/views/collection/index.php | 770 +++--- themes/default/views/collection/modifyRow.php | 72 +- .../default/views/collection/queryHistory.php | 18 +- .../views/collection/removeCollection.php | 6 +- themes/default/views/db/addUser.php | 28 +- themes/default/views/db/auth.php | 25 +- themes/default/views/db/dbExport.php | 60 +- themes/default/views/db/dbImport.php | 43 +- themes/default/views/db/dbTransfer.php | 140 +- themes/default/views/db/dropDatabase.php | 7 +- .../default/views/db/dropDatabaseResult.php | 12 +- themes/default/views/db/index.php | 75 +- themes/default/views/db/newCollection.php | 32 +- themes/default/views/db/profile.php | 13 +- themes/default/views/db/profileLevel.php | 60 +- themes/default/views/db/repairDatabase.php | 6 +- themes/default/views/exception.php | 4 +- themes/default/views/footer.php | 1 - themes/default/views/header.php | 37 +- themes/default/views/login/index.php | 187 +- themes/default/views/login/index.php.old | 90 + themes/default/views/server/command.php | 50 +- .../default/views/server/createDatabase.php | 31 +- themes/default/views/server/databases.php | 23 +- themes/default/views/server/execute.php | 93 +- themes/default/views/server/index.php | 69 +- themes/default/views/server/killOp.php | 12 +- themes/default/views/server/processlist.php | 72 +- themes/default/views/server/replication.php | 72 +- themes/default/views/server/status.php | 12 +- 153 files changed, 12604 insertions(+), 8332 deletions(-) create mode 100644 .idea/.name create mode 100644 .idea/cssxfire.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/libraries/sass_stdlib.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/rockmongo.iml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml create mode 100644 app/lib/mongo/mongo.php delete mode 100644 js/jquery-1.4.2.min.js create mode 100644 js/jquery-1.8.2.min.js create mode 100644 themes/default/css/base.css create mode 100644 themes/default/css/grids.css create mode 100644 themes/default/css/mixins.css create mode 100644 themes/default/css/style.css create mode 100644 themes/default/css/variables.css create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_appearance.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_background-clip.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_background-origin.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_background-size.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_border-radius.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_box-shadow.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_box-sizing.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_box.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_columns.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_filter.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_font-face.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_hyphenation.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_images.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_inline-block.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_opacity.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_regions.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_shared.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_text-shadow.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_transform.scssc create mode 100644 themes/default/sass/.sass-cache/06322f8c605d3f02039b0e4aa3d960b1af943bb1/_transition.scssc create mode 100644 themes/default/sass/.sass-cache/1283a76f4bfbe9c87f0f2c0d002f3a94f809e104/_hacks.scssc create mode 100644 themes/default/sass/.sass-cache/58bd07bd1606c5126fdfb8ad8f067fbb436b2d7e/_css3.scssc create mode 100644 themes/default/sass/.sass-cache/58bd07bd1606c5126fdfb8ad8f067fbb436b2d7e/_reset.scssc create mode 100644 themes/default/sass/.sass-cache/58bd07bd1606c5126fdfb8ad8f067fbb436b2d7e/_support.scssc create mode 100644 themes/default/sass/.sass-cache/b819dcfad281a5202e57aaa1519a28cf711f13fb/_utilities.scssc create mode 100644 themes/default/sass/.sass-cache/e13a813f4fd520ff66f68a111b9ae6bb77300817/base.scssc create mode 100644 themes/default/sass/.sass-cache/e13a813f4fd520ff66f68a111b9ae6bb77300817/grids.scssc create mode 100644 themes/default/sass/.sass-cache/e13a813f4fd520ff66f68a111b9ae6bb77300817/mixins.scssc create mode 100644 themes/default/sass/.sass-cache/e13a813f4fd520ff66f68a111b9ae6bb77300817/style.scssc create mode 100644 themes/default/sass/.sass-cache/e13a813f4fd520ff66f68a111b9ae6bb77300817/variables.scssc create mode 100644 themes/default/sass/base.scss create mode 100644 themes/default/sass/grids.scss create mode 100644 themes/default/sass/mixins.scss create mode 100644 themes/default/sass/style.scss create mode 100644 themes/default/sass/variables.scss create mode 100644 themes/default/views/login/index.php.old diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..7b1648e --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +rockmongo \ No newline at end of file diff --git a/.idea/cssxfire.xml b/.idea/cssxfire.xml new file mode 100644 index 0000000..f4acc38 --- /dev/null +++ b/.idea/cssxfire.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/sass_stdlib.xml b/.idea/libraries/sass_stdlib.xml new file mode 100644 index 0000000..546bfd1 --- /dev/null +++ b/.idea/libraries/sass_stdlib.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..13fc001 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + jar:file:\C:\Program Files (x86)\JetBrains\PhpStorm 5.0.1\lib\webide.jar!\resources\html5-schema\html5.rnc + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9258fbb --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/rockmongo.iml b/.idea/rockmongo.iml new file mode 100644 index 0000000..6b8184f --- /dev/null +++ b/.idea/rockmongo.iml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..c80f219 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..e869b63 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,791 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1356934675175 + 1356934675175 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/classes/BaseController.php b/app/classes/BaseController.php index 6f75fa1..f9e08b7 100644 --- a/app/classes/BaseController.php +++ b/app/classes/BaseController.php @@ -20,22 +20,24 @@ import("classes.VarEval"); //filter $MONGO -if (class_exists("RFilter")) { +if (class_exists("RFilter")) +{ global $MONGO; RFilter::apply("CONFIG_FILTER", $MONGO); } -class BaseController extends RExtController { +class BaseController extends RExtController +{ /** * Enter description here... - * + * * @var MServer */ protected $_server; - + /** * Enter description here ... - * + * * @var RMongo */ protected $_mongo; @@ -47,102 +49,120 @@ class BaseController extends RExtController { */ protected $_admin; protected $_logQuery = false; - + /** called before any actions **/ - public function onBefore() { + public function onBefore() + { global $MONGO; - + //exception handler set_exception_handler(array($this, "exceptionHandler")); - + $this->_admin = MUser::userInSession(); - if (!$this->_admin) { + if (!$this->_admin) + { //if user is loged in? $server = MServer::serverWithIndex(xi("host")); - + //filter server plugins - if (class_exists("RFilter")) { + if (class_exists("RFilter")) + { RFilter::apply("SERVER_FILTER", $server); } - + //if auth is disabled - if ($server && !$server->mongoAuth() && !$server->controlAuth()) { + if ($server && !$server->mongoAuth() && !$server->controlAuth()) + { MUser::login("rockmongo_memo", "rockmongo_memo", xi("host"), "admin", 10800); $this->_admin = MUser::userInSession(); } - else { - $this->redirect("login.index", array( "host" => xi("host"))); + else + { + $this->redirect("login.index", array("host" => xi("host"))); } } - if (!$this->_admin->validate()) { - $this->redirect("login.index", array( "host" => $this->_admin->hostIndex() )); + if (!$this->_admin->validate()) + { + $this->redirect("login.index", array("host" => $this->_admin->hostIndex())); } $this->_server = MServer::serverWithIndex($this->_admin->hostIndex()); $this->_mongo = $this->_server->mongo(); - + //log query - if (isset($MONGO["features"]["log_query"]) && $MONGO["features"]["log_query"] == "on") { + if (isset($MONGO["features"]["log_query"]) && $MONGO["features"]["log_query"] == "on") + { $this->_logQuery = true; } - + //render header - if (!$this->isAjax()) { + if (!$this->isAjax()) + { render_view("header"); } } /** called after action call **/ - public function onAfter() { - if (!$this->isAjax()) { + public function onAfter() + { + if (!$this->isAjax()) + { render_view("footer"); } } - + /** * handle exception in runtime * * @param Exception $exception exception to handle */ - public function exceptionHandler($exception) { + public function exceptionHandler($exception) + { $message = $exception->getMessage(); - render_view("exception", array( "message" => $message )); + render_view("exception", array("message" => $message)); render_view("footer"); exit(); } - + /** * convert variable from string values * * @param MongoDB $mongodb MongoDB instance - * @param string $dataType data type - * @param string $format string format - * @param string $value string value + * @param string $dataType data type + * @param string $format string format + * @param string $value string value * @param integer $integerValue integer value - * @param long $longValue long value - * @param string $doubleValue float value - * @param string $boolValue boolea value - * @param string $mixedValue mixed value (array or object) + * @param long $longValue long value + * @param string $doubleValue float value + * @param string $boolValue boolea value + * @param string $mixedValue mixed value (array or object) + * * @return mixed * @throws Exception */ - protected function _convertValue($mongodb, $dataType, $format, $value, $integerValue, $longValue, $doubleValue, $boolValue, $mixedValue) { + protected function _convertValue($mongodb, $dataType, $format, $value, $integerValue, $longValue, $doubleValue, $boolValue, $mixedValue) + { $realValue = null; - switch ($dataType) { + switch ($dataType) + { case "integer": - if (class_exists("MongoInt32")) { + if (class_exists("MongoInt32")) + { $realValue = new MongoInt32($integerValue); } - else { + else + { $realValue = intval($realValue); } break; case "long": - if (class_exists("MongoInt64")) { + if (class_exists("MongoInt64")) + { $realValue = new MongoInt64($longValue); - } - else { + } + else + { $realValue = $longValue; - } + } break; case "float": case "double": @@ -160,65 +180,76 @@ protected function _convertValue($mongodb, $dataType, $format, $value, $integerV case "mixed": $eval = new VarEval($mixedValue, $format, $mongodb); $realValue = $eval->execute(); - if ($realValue === false) { + if ($realValue === false) + { throw new Exception("Unable to parse mixed value, just check syntax!"); } break; } return $realValue; } - - protected function _encodeJson($var) { - if (function_exists("json_encode")) { + + protected function _encodeJson($var) + { + if (function_exists("json_encode")) + { return json_encode($var); } import("classes.Services_JSON"); $service = new Services_JSON(); return $service->encode($var); } - + /** * Output variable as JSON * - * @param mixed $var variable + * @param mixed $var variable * @param boolean $exit if exit after output */ - protected function _outputJson($var, $exit = true) { + protected function _outputJson($var, $exit = true) + { echo $this->_encodeJson($var); - if ($exit) { + if ($exit) + { exit(); } } - - protected function _decodeJson($var) { + + protected function _decodeJson($var) + { import("classes.Services_JSON"); $service = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $ret = array(); $decode = $service->decode($var); return $decode; - } - + } + /** * Export var as string then highlight it. * - * @param mixed $var variable to be exported - * @param string $format data format, array|json + * @param mixed $var variable to be exported + * @param string $format data format, array|json * @param boolean $label if add label to field + * * @return string */ - protected function _highlight($var, $format = "array", $label = false) { + protected function _highlight($var, $format = "array", $label = false) + { import("classes.VarExportor"); $exportor = new VarExportor($this->_mongo->selectDB("admin"), $var); $varString = $exportor->export($format, $label); $string = null; - if ($format == "array") { + if ($format == "array") + { $string = highlight_string("<?php ', "/") . "/", '', $string, 1); } - else { - $string = json_format_html($varString); + else + { + $string = json_format_html($varString); } - if ($label) { + if ($label) + { $id = addslashes(isset($var["_id"]) ? rock_id_string($var["_id"]) : ""); $string = preg_replace_callback("/(['\"])rockfield\.(.+)\.rockfield(['\"])/U", create_function('$match', ' $fields = explode(".rockfield.", $match[2]); return "" . $match[1] . array_pop($fields) . $match[3] . "";'), $string); @@ -228,76 +259,90 @@ protected function _highlight($var, $format = "array", $label = false) { } return $string; } - - /** - * format bytes to human size - * + + /** + * format bytes to human size + * * @param integer $bytes size in byte + * * @return string size in k, m, g.. **/ - protected function _formatBytes($bytes) { - if ($bytes < 1024) { + protected function _formatBytes($bytes) + { + if ($bytes < 1024) + { return $bytes; } - if ($bytes < 1024 * 1024) { - return round($bytes/1024, 2) . "k"; + if ($bytes < 1024 * 1024) + { + return round($bytes / 1024, 2) . "k"; } - if ($bytes < 1024 * 1024 * 1024) { - return round($bytes/1024/1024, 2) . "m"; + if ($bytes < 1024 * 1024 * 1024) + { + return round($bytes / 1024 / 1024, 2) . "m"; } - if ($bytes < 1024 * 1024 * 1024 * 1024) { - return round($bytes/1024/1024/1024, 2) . "g"; + if ($bytes < 1024 * 1024 * 1024 * 1024) + { + return round($bytes / 1024 / 1024 / 1024, 2) . "g"; } return $bytes; } - + /** * Enter description here... * - * @param MongoDB $db + * @param MongoDB $db * @param unknown_type $from * @param unknown_type $to * @param unknown_type $index */ - protected function _copyCollection($db, $from, $to, $index = true) { - if ($index) { + protected function _copyCollection($db, $from, $to, $index = true) + { + if ($index) + { $indexes = $db->selectCollection($from)->getIndexInfo(); - foreach ($indexes as $index) { + foreach ($indexes as $index) + { $options = array(); - if (isset($index["unique"])) { + if (isset($index["unique"])) + { $options["unique"] = $index["unique"]; } - if (isset($index["name"])) { + if (isset($index["name"])) + { $options["name"] = $index["name"]; } - if (isset($index["background"])) { + if (isset($index["background"])) + { $options["background"] = $index["background"]; } - if (isset($index["dropDups"])) { + if (isset($index["dropDups"])) + { $options["dropDups"] = $index["dropDups"]; } $db->selectCollection($to)->ensureIndex($index["key"], $options); } } - $ret = $db->execute('function (coll, coll2) { return db.getCollection(coll).copyTo(coll2);}', array( $from, $to )); + $ret = $db->execute('function (coll, coll2) { return db.getCollection(coll).copyTo(coll2);}', array($from, $to)); return $ret["ok"]; - } - - protected function _logFile($db, $collection) { + } + + protected function _logFile($db, $collection) + { $logDir = dirname(__ROOT__) . DS . "logs"; return $logDir . DS . urlencode($this->_admin) . "-query-" . urlencode($db) . "-" . urlencode($collection) . ".php"; } - + /** * remember data format choice * * @param string $format data format */ - protected function _rememberFormat($format) { + protected function _rememberFormat($format) + { setcookie("rock_format", $format, time() + 365 * 86400, "/"); } } - ?> \ No newline at end of file diff --git a/app/classes/Services_JSON.php b/app/classes/Services_JSON.php index 84a9a33..1e98821 100644 --- a/app/classes/Services_JSON.php +++ b/app/classes/Services_JSON.php @@ -58,22 +58,22 @@ /** * Marker constant for Services_JSON::decode(), used to flag stack state */ -define('SERVICES_JSON_SLICE', 1); +define('SERVICES_JSON_SLICE', 1); /** * Marker constant for Services_JSON::decode(), used to flag stack state */ -define('SERVICES_JSON_IN_STR', 2); +define('SERVICES_JSON_IN_STR', 2); /** * Marker constant for Services_JSON::decode(), used to flag stack state */ -define('SERVICES_JSON_IN_ARR', 3); +define('SERVICES_JSON_IN_ARR', 3); /** * Marker constant for Services_JSON::decode(), used to flag stack state */ -define('SERVICES_JSON_IN_OBJ', 4); +define('SERVICES_JSON_IN_OBJ', 4); /** * Marker constant for Services_JSON::decode(), used to flag stack state @@ -113,756 +113,798 @@ */ class Services_JSON { - /** - * constructs a new JSON instance - * - * @param int $use object behavior flags; combine with boolean-OR - * - * possible values: - * - SERVICES_JSON_LOOSE_TYPE: loose typing. - * "{...}" syntax creates associative arrays - * instead of objects in decode(). - * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. - * Values which can't be encoded (e.g. resources) - * appear as NULL instead of throwing errors. - * By default, a deeply-nested resource will - * bubble up with an error, so all return values - * from encode() should be checked with isError() - */ - function Services_JSON($use = 0) - { - $this->use = $use; - } - - /** - * convert a string from one UTF-16 char to one UTF-8 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 $utf16 UTF-16 character - * @return string UTF-8 character - * @access private - */ - function utf162utf8($utf16) - { - // oh please oh please oh please oh please oh please - if(function_exists('mb_convert_encoding')) { - return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); - } - - $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); - - switch(true) { - case ((0x7F & $bytes) == $bytes): - // 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 chr(0x7F & $bytes); - - case (0x07FF & $bytes) == $bytes: - // return a 2-byte UTF-8 character - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0xC0 | (($bytes >> 6) & 0x1F)) - . chr(0x80 | ($bytes & 0x3F)); - - case (0xFFFF & $bytes) == $bytes: - // return a 3-byte UTF-8 character - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0xE0 | (($bytes >> 12) & 0x0F)) - . chr(0x80 | (($bytes >> 6) & 0x3F)) - . chr(0x80 | ($bytes & 0x3F)); - } - - // ignoring UTF-32 for now, sorry - return ''; - } - - /** - * 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 - */ - function 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 (and sends JSON Header) - * - * @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 - */ - function encode($var) - { - //header('Content-type: application/json'); - return $this->encodeUnsafe($var); - } - /** - * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow CSS!!!!) - * - * @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 - */ - function encodeUnsafe($var) - { - // see bug #16908 - regarding numeric locale printing - $lc = setlocale(LC_NUMERIC, 0); - setlocale(LC_NUMERIC, 'C'); - $ret = $this->_encode($var); - setlocale(LC_NUMERIC, $lc); - return $ret; - - } - /** - * PRIVATE CODE that does the work of 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 - */ - function _encode($var) - { - - 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 - if ($c+1 >= $strlen_var) { - $c += 1; - $ascii .= '?'; - break; - } - - $char = pack('C*', $ord_var_c, ord($var{$c + 1})); - $c += 1; - $utf16 = $this->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF0) == 0xE0): - if ($c+2 >= $strlen_var) { - $c += 2; - $ascii .= '?'; - break; - } - // 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->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF8) == 0xF0): - if ($c+3 >= $strlen_var) { - $c += 3; - $ascii .= '?'; - break; - } - // 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->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 - if ($c+4 >= $strlen_var) { - $c += 4; - $ascii .= '?'; - break; - } - $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->utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFE) == 0xFC): - if ($c+5 >= $strlen_var) { - $c += 5; - $ascii .= '?'; - break; - } - // 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->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))) { - $properties = array_map(array($this, 'name_value'), - array_keys($var), - array_values($var)); - - foreach($properties as $property) { - if(Services_JSON::isError($property)) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - } - - // treat it like a regular array - $elements = array_map(array($this, '_encode'), $var); - - foreach($elements as $element) { - if(Services_JSON::isError($element)) { - return $element; - } - } - - return '[' . join(',', $elements) . ']'; - - case 'object': - $vars = get_object_vars($var); - - $properties = array_map(array($this, 'name_value'), - array_keys($vars), - array_values($vars)); - - foreach($properties as $property) { - if(Services_JSON::isError($property)) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - - default: - return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) - ? 'null' - : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); - } - } - - /** - * 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 - */ - function name_value($name, $value) - { - $encoded_value = $this->_encode($value); - - if(Services_JSON::isError($encoded_value)) { - return $encoded_value; - } - - return $this->_encode(strval($name)) . ':' . $encoded_value; - } - - /** - * reduce a string by removing leading and trailing comments and whitespace - * - * @param $str string string value to strip of comments and whitespace - * - * @return string string value stripped of comments and whitespace - * @access private - */ - function reduce_string($str) - { - $str = preg_replace(array( - - // eliminate single line comments in '// ...' form - '#^\s*//(.+)$#m', - - // eliminate multi-line comments in '/* ... */' form, at start of string - '#^\s*/\*(.+)\*/#Us', - - // eliminate multi-line comments in '/* ... */' form, at end of string - '#/\*(.+)\*/\s*$#Us' - - ), '', $str); - - // eliminate extraneous space - return trim($str); - } - - /** - * decodes a JSON string into appropriate variable - * - * @param string $str JSON-formatted string - * - * @return mixed number, boolean, string, array, or object - * corresponding to given JSON input string. - * See argument 1 to Services_JSON() above for object-output behavior. - * Note that decode() always returns strings - * in ASCII or UTF-8 format! - * @access public - */ - function decode($str) - { - $str = $this->reduce_string($str); - - switch (strtolower($str)) { - case 'true': - return true; - - case 'false': - return false; - - case 'null': - return null; - - default: - $m = array(); - - if (is_numeric($str)) { - // Lookie-loo, it's a number - - // This would work on its own, but I'm trying to be - // good about returning integers where appropriate: - // return (float)$str; - - // Return float or int, as appropriate - return ((float)$str == (integer)$str) - ? (integer)$str - : (float)$str; - - } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { - // STRINGS RETURNED IN UTF-8 FORMAT - $delim = substr($str, 0, 1); - $chrs = substr($str, 1, -1); - $utf8 = ''; - $strlen_chrs = strlen($chrs); - - for ($c = 0; $c < $strlen_chrs; ++$c) { - - $substr_chrs_c_2 = substr($chrs, $c, 2); - $ord_chrs_c = ord($chrs{$c}); - - switch (true) { - case $substr_chrs_c_2 == '\b': - $utf8 .= chr(0x08); - ++$c; - break; - case $substr_chrs_c_2 == '\t': - $utf8 .= chr(0x09); - ++$c; - break; - case $substr_chrs_c_2 == '\n': - $utf8 .= chr(0x0A); - ++$c; - break; - case $substr_chrs_c_2 == '\f': - $utf8 .= chr(0x0C); - ++$c; - break; - case $substr_chrs_c_2 == '\r': - $utf8 .= chr(0x0D); - ++$c; - break; - - case $substr_chrs_c_2 == '\\"': - case $substr_chrs_c_2 == '\\\'': - case $substr_chrs_c_2 == '\\\\': - case $substr_chrs_c_2 == '\\/': - if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || - ($delim == "'" && $substr_chrs_c_2 != '\\"')) { - $utf8 .= $chrs{++$c}; - } - break; - - case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): - // single, escaped unicode character - $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) - . chr(hexdec(substr($chrs, ($c + 4), 2))); - $utf8 .= $this->utf162utf8($utf16); - $c += 5; - break; - - case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): - $utf8 .= $chrs{$c}; - break; - - case ($ord_chrs_c & 0xE0) == 0xC0: - // characters U-00000080 - U-000007FF, mask 110XXXXX - //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 2); - ++$c; - break; - - case ($ord_chrs_c & 0xF0) == 0xE0: - // characters U-00000800 - U-0000FFFF, mask 1110XXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 3); - $c += 2; - break; - - case ($ord_chrs_c & 0xF8) == 0xF0: - // characters U-00010000 - U-001FFFFF, mask 11110XXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 4); - $c += 3; - break; - - case ($ord_chrs_c & 0xFC) == 0xF8: - // characters U-00200000 - U-03FFFFFF, mask 111110XX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 5); - $c += 4; - break; - - case ($ord_chrs_c & 0xFE) == 0xFC: - // characters U-04000000 - U-7FFFFFFF, mask 1111110X - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $utf8 .= substr($chrs, $c, 6); - $c += 5; - break; - - } - - } - - return $utf8; - - } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { - // array, or object notation - - if ($str{0} == '[') { - $stk = array(SERVICES_JSON_IN_ARR); - $arr = array(); - } else { - if ($this->use & SERVICES_JSON_LOOSE_TYPE) { - $stk = array(SERVICES_JSON_IN_OBJ); - $obj = array(); - } else { - $stk = array(SERVICES_JSON_IN_OBJ); - $obj = new stdClass(); - } - } - - array_push($stk, array('what' => SERVICES_JSON_SLICE, - 'where' => 0, - 'delim' => false)); - - $chrs = substr($str, 1, -1); - $chrs = $this->reduce_string($chrs); - - if ($chrs == '') { - if (reset($stk) == SERVICES_JSON_IN_ARR) { - return $arr; - - } else { - return $obj; - - } - } - - //print("\nparsing {$chrs}\n"); - - $strlen_chrs = strlen($chrs); - - for ($c = 0; $c <= $strlen_chrs; ++$c) { - - $top = end($stk); - $substr_chrs_c_2 = substr($chrs, $c, 2); - - if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { - // found a comma that is not inside a string, array, etc., - // OR we've reached the end of the character list - $slice = substr($chrs, $top['where'], ($c - $top['where'])); - array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); - //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - if (reset($stk) == SERVICES_JSON_IN_ARR) { - // we are in an array, so just push an element onto the stack - array_push($arr, $this->decode($slice)); - - } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { - // we are in an object, so figure - // out the property name and set an - // element in an associative array, - // for now - $parts = array(); - - if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { - // "name":value pair - $key = $this->decode($parts[1]); - $val = $this->decode($parts[2]); - - if ($this->use & SERVICES_JSON_LOOSE_TYPE) { - $obj[$key] = $val; - } else { - $obj->$key = $val; - } - } elseif (preg_match('/^\s*([$\w]+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {//iwind:add char "$" to sequence - // name:value pair, where name is unquoted - $key = $parts[1]; - $val = $this->decode($parts[2]); - - if ($this->use & SERVICES_JSON_LOOSE_TYPE) { - $obj[$key] = $val; - } else { - $obj->$key = $val; - } - } - - } - - } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { - // found a quote, and we are not inside a string - array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); - //print("Found start of string at {$c}\n"); - - } elseif (($chrs{$c} == $top['delim']) && - ($top['what'] == SERVICES_JSON_IN_STR) && - ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { - // found a quote, we're in a string, and it's not escaped - // we know that it's not escaped becase there is _not_ an - // odd number of backslashes at the end of the string so far - array_pop($stk); - //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); - - } elseif (($chrs{$c} == '[') && - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { - // found a left-bracket, and we are in an array, object, or slice - array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); - //print("Found start of array at {$c}\n"); - - } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { - // found a right-bracket, and we're in an array - array_pop($stk); - //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - } elseif (($chrs{$c} == '{') && - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { - // found a left-brace, and we are in an array, object, or slice - array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); - //print("Found start of object at {$c}\n"); - - } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { - // found a right-brace, and we're in an object - array_pop($stk); - //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - } elseif (($substr_chrs_c_2 == '/*') && - in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { - // found a comment start, and we are in an array, object, or slice - array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); - $c++; - //print("Found start of comment at {$c}\n"); - - } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { - // found a comment end, and we're in one now - array_pop($stk); - $c++; - - for ($i = $top['where']; $i <= $c; ++$i) - $chrs = substr_replace($chrs, ' ', $i, 1); - - //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); - - } - - } - - if (reset($stk) == SERVICES_JSON_IN_ARR) { - return $arr; - - } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { - return $obj; - - } - - } - } - } - - /** - * @todo Ultimately, this should just call PEAR::isError() - */ - function isError($data, $code = null) - { - if (class_exists('pear')) { - return PEAR::isError($data, $code); - } elseif (is_object($data) && (get_class($data) == 'services_json_error' || - is_subclass_of($data, 'services_json_error'))) { - return true; - } - - return false; - } + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 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 $utf16 UTF-16 character + * + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if (function_exists('mb_convert_encoding')) + { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch (true) + { + case ((0x7F & $bytes) == $bytes): + // 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 chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) . chr(0x80 | (($bytes >> 6) & 0x3F)) . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * 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 + */ + function 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 (and sends JSON Header) + * + * @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 + */ + function encode($var) + { + //header('Content-type: application/json'); + return $this->encodeUnsafe($var); + } + + /** + * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow CSS!!!!) + * + * @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 + */ + function encodeUnsafe($var) + { + // see bug #16908 - regarding numeric locale printing + $lc = setlocale(LC_NUMERIC, 0); + setlocale(LC_NUMERIC, 'C'); + $ret = $this->_encode($var); + setlocale(LC_NUMERIC, $lc); + return $ret; + + } + + /** + * PRIVATE CODE that does the work of 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 + */ + function _encode($var) + { + + 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 + if ($c + 1 >= $strlen_var) + { + $c += 1; + $ascii .= '?'; + break; + } + + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + if ($c + 2 >= $strlen_var) + { + $c += 2; + $ascii .= '?'; + break; + } + // 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->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + if ($c + 3 >= $strlen_var) + { + $c += 3; + $ascii .= '?'; + break; + } + // 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->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 + if ($c + 4 >= $strlen_var) + { + $c += 4; + $ascii .= '?'; + break; + } + $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->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + if ($c + 5 >= $strlen_var) + { + $c += 5; + $ascii .= '?'; + break; + } + // 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->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))) + { + $properties = array_map(array($this, 'name_value'), array_keys($var), array_values($var)); + + foreach ($properties as $property) + { + if (Services_JSON::isError($property)) + { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, '_encode'), $var); + + foreach ($elements as $element) + { + if (Services_JSON::isError($element)) + { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), array_keys($vars), array_values($vars)); + + foreach ($properties as $property) + { + if (Services_JSON::isError($property)) + { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) ? 'null' : new Services_JSON_Error(gettype($var) . " can not be encoded as JSON string"); + } + } + + /** + * 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 + */ + function name_value($name, $value) + { + $encoded_value = $this->_encode($value); + + if (Services_JSON::isError($encoded_value)) + { + return $encoded_value; + } + + return $this->_encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) + { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) + { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) ? (integer)$str : (float)$str; + + } + elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) + { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) + { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) + { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || ($delim == "'" && $substr_chrs_c_2 != '\\"')) + { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } + elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) + { + // array, or object notation + + if ($str{0} == '[') + { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } + else + { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) + { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } + else + { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => 0, 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') + { + if (reset($stk) == SERVICES_JSON_IN_ARR) + { + return $arr; + + } + else + { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) + { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) + { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) + { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } + elseif (reset($stk) == SERVICES_JSON_IN_OBJ) + { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) + { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) + { + $obj[$key] = $val; + } + else + { + $obj->$key = $val; + } + } + elseif (preg_match('/^\s*([$\w]+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) + { //iwind:add char "$" to sequence + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) + { + $obj[$key] = $val; + } + else + { + $obj->$key = $val; + } + } + + } + + } + elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) + { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } + elseif (($chrs{$c} == $top['delim']) && ($top['what'] == SERVICES_JSON_IN_STR) && ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) + { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } + elseif (($chrs{$c} == '[') && in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) + { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } + elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) + { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + elseif (($chrs{$c} == '{') && in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) + { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } + elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) + { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + elseif (($substr_chrs_c_2 == '/*') && in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) + { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } + elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) + { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + { + $chrs = substr_replace($chrs, ' ', $i, 1); + } + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) + { + return $arr; + + } + elseif (reset($stk) == SERVICES_JSON_IN_OBJ) + { + return $obj; + + } + + } + } + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) + { + return PEAR::isError($data, $code); + } + elseif (is_object($data) && (get_class($data) == 'services_json_error' || is_subclass_of($data, 'services_json_error'))) + { + return true; + } + + return false; + } } -if (class_exists('PEAR_Error')) { +if (class_exists('PEAR_Error')) +{ - class Services_JSON_Error extends PEAR_Error - { - function Services_JSON_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) - { - parent::PEAR_Error($message, $code, $mode, $options, $userinfo); - } - } + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, $mode = null, $options = null, $userinfo = null) + { + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); + } + } -} else { +} +else +{ - /** - * @todo Ultimately, this class shall be descended from PEAR_Error - */ - class Services_JSON_Error - { - function Services_JSON_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) - { + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, $mode = null, $options = null, $userinfo = null) + { - } - } + } + } } - + ?> \ No newline at end of file diff --git a/app/classes/VarEval.php b/app/classes/VarEval.php index dab1352..e024f64 100644 --- a/app/classes/VarEval.php +++ b/app/classes/VarEval.php @@ -3,97 +3,83 @@ * eval source code in PHP or JSON format * */ -class VarEval { +class VarEval +{ /** * Source to run - * + * * @var string */ private $_source; - + /** * Source Format - * + * * @var string */ private $_format; - + /** * current MongoDB * * @var MongoDB */ private $_db; - - function __construct($source, $format = "array", MongoDB $db = null) { + + function __construct($source, $format = "array", MongoDB $db = null) + { $this->_source = $source; - + $this->_format = $format; - if (!$this->_format) { + if (!$this->_format) + { $this->_format = "array"; } - + $this->_db = $db; } - + /** * execute the code * * @return mixed */ - function execute() { - if ($this->_format == "array") { + function execute() + { + if ($this->_format == "array") + { return $this->_runPHP(); } - else if ($this->_format == "json") { + else if ($this->_format == "json") + { return $this->_runJson(); } } - - private function _runPHP() { + + private function _runPHP() + { $this->_source = "return " . $this->_source . ";"; - if (function_exists("token_get_all")) {//tokenizer extension may be disabled + if (function_exists("token_get_all")) + { //tokenizer extension may be disabled $php = "_source . "\n?>"; $tokens = token_get_all($php); - foreach ($tokens as $token) { + foreach ($tokens as $token) + { $type = $token[0]; - if (is_long($type)) { - if (in_array($type, array( - T_OPEN_TAG, - T_RETURN, - T_WHITESPACE, - T_ARRAY, - T_LNUMBER, - T_DNUMBER, - T_CONSTANT_ENCAPSED_STRING, - T_DOUBLE_ARROW, - T_CLOSE_TAG, - T_NEW, - T_DOUBLE_COLON - ))) { + if (is_long($type)) + { + if (in_array($type, array(T_OPEN_TAG, T_RETURN, T_WHITESPACE, T_ARRAY, T_LNUMBER, T_DNUMBER, T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_ARROW, T_CLOSE_TAG, T_NEW, T_DOUBLE_COLON))) + { continue; } - - if ($type == T_STRING) { + + if ($type == T_STRING) + { $func = strtolower($token[1]); - if (in_array($func, array( - //keywords allowed - "mongoid", - "mongocode", - "mongodate", - "mongoregex", - "mongobindata", - "mongoint32", - "mongoint64", - "mongodbref", - "mongominkey", - "mongomaxkey", - "mongotimestamp", - "true", - "false", - "null", - "__set_state" - ))) { + if (in_array($func, array(//keywords allowed + "mongoid", "mongocode", "mongodate", "mongoregex", "mongobindata", "mongoint32", "mongoint64", "mongodbref", "mongominkey", "mongomaxkey", "mongotimestamp", "true", "false", "null", "__set_state")) + ) + { continue; } } @@ -103,8 +89,9 @@ private function _runPHP() { } return eval($this->_source); } - - private function _runJson() { + + private function _runJson() + { $timezone = @date_default_timezone_get(); date_default_timezone_set("UTC"); $ret = $this->_db->execute('function () { @@ -139,10 +126,10 @@ function ISODate (isoDateStr) { return new Date(time); }; } - return ' . $this->_source . ';}' - ); + return ' . $this->_source . ';}'); date_default_timezone_set($timezone); - if ($ret["ok"]) { + if ($ret["ok"]) + { return $ret["retval"]; } return false; diff --git a/app/classes/VarExportor.php b/app/classes/VarExportor.php index 8776a56..6b5aa6f 100644 --- a/app/classes/VarExportor.php +++ b/app/classes/VarExportor.php @@ -3,7 +3,8 @@ define("MONGO_EXPORT_PHP", "array"); define("MONGO_EXPORT_JSON", "json"); -class VarExportor { +class VarExportor +{ private $_db; private $_var; private $_phpParams = array(); @@ -14,130 +15,157 @@ class VarExportor { * construct exportor * * @param MongoDB $db current db you are operating - * @param mixed $var variable + * @param mixed $var variable */ - function __construct(MongoDB $db, $var) { + function __construct(MongoDB $db, $var) + { $this->_db = $db; $this->_var = $var; } - + /** * Export the variable to a string * - * @param string $type variable type (array or json) + * @param string $type variable type (array or json) * @param boolean $fieldLabel if add label to fields + * * @return string */ - function export($type = MONGO_EXPORT_PHP, $fieldLabel = false) { - if ($fieldLabel) { + function export($type = MONGO_EXPORT_PHP, $fieldLabel = false) + { + if ($fieldLabel) + { $this->_var = $this->_addLabelToArray($this->_var); } - if ($type == MONGO_EXPORT_PHP) { + if ($type == MONGO_EXPORT_PHP) + { return $this->_exportPHP(); } return $this->_exportJSON(); } - - private function _exportPHP() { + + private function _exportPHP() + { $var = $this->_formatVar($this->_var); $string = var_export($var, true); $params = array(); - foreach ($this->_phpParams as $index => $value) { + foreach ($this->_phpParams as $index => $value) + { $params["'" . $this->_param($index) . "'"] = $value; } return strtr($string, $params); } - + /** * Enter description here... * * @param unknown_type $str * @param unknown_type $from * @param unknown_type $len + * * @return unknown * @author sajjad at sajjad dot biz (copied from PHP manual) */ - private function _utf8_substr($str,$from,$len) { - return function_exists('mb_substr') ? - mb_substr($str, $from, $len, 'UTF-8') : - preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'. $from .'}'.'((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'. $len .'}).*#s','$1', $str); + private function _utf8_substr($str, $from, $len) + { + return function_exists('mb_substr') ? mb_substr($str, $from, $len, 'UTF-8') : preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,' . $from . '}' . '((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,' . $len . '}).*#s', '$1', $str); } - - private function _addLabelToArray($array, $prev = "") { + + private function _addLabelToArray($array, $prev = "") + { $ret = array(); $cutLength = 150; - foreach ($array as $key => $value) { - if (is_string($key) || is_int($key) || is_float($key)) { - $newKey = $prev . ($prev === ""?"":".") . "rockfield." . $key; - if (is_string($value) && strlen($value) > $cutLength) { + foreach ($array as $key => $value) + { + if (is_string($key) || is_int($key) || is_float($key)) + { + $newKey = $prev . ($prev === "" ? "" : ".") . "rockfield." . $key; + if (is_string($value) && strlen($value) > $cutLength) + { $value = $this->_utf8_substr($value, 0, $cutLength); $value = $value . " __rockmore.{$newKey}.rockmore__"; } $ret[$newKey . ".rockfield"] = $value; - if (is_array($value)) { + if (is_array($value)) + { $ret[$newKey . ".rockfield"] = $this->_addLabelToArray($value, $newKey); } } - else { + else + { $ret[$key] = $value; } } return $ret; } - private function _exportJSON() { - if (function_exists('json_encode')) { - $service = 'json_encode'; - } else { - import("classes.Services_JSON"); - $json = new Services_JSON(); - $service = array(&$json, 'encode'); + private function _exportJSON() + { + if (function_exists('json_encode')) + { + $service = 'json_encode'; + } + else + { + import("classes.Services_JSON"); + $json = new Services_JSON(); + $service = array(&$json, 'encode'); } $var = $this->_formatVarAsJSON($this->_var, $service); $string = call_user_func($service, $var); - $params = array(); - foreach ($this->_jsonParams as $index => $value) { - $params['"' . $this->_param($index) . '"'] = $value; + $params = array(); + foreach ($this->_jsonParams as $index => $value) + { + $params['"' . $this->_param($index) . '"'] = $value; } return json_unicode_to_utf8(json_format(strtr($string, $params))); } - - private function _param($index) { - return "%{MONGO_PARAM_{$index}}"; + + private function _param($index) + { + return "%{MONGO_PARAM_{$index}}"; } - - private function _formatVar($var) { - if (is_scalar($var) || is_null($var)) { - switch (gettype($var)) { + + private function _formatVar($var) + { + if (is_scalar($var) || is_null($var)) + { + switch (gettype($var)) + { case "integer": - if (class_exists("MongoInt32")) { - // producing MongoInt32 to keep type unchanged (Kyryl Bilokurov ) - $this->_paramIndex ++; - $this->_phpParams[$this->_paramIndex] = 'new MongoInt32(' . $var . ')'; - return $this->_param($this->_paramIndex); - } + if (class_exists("MongoInt32")) + { + // producing MongoInt32 to keep type unchanged (Kyryl Bilokurov ) + $this->_paramIndex++; + $this->_phpParams[$this->_paramIndex] = 'new MongoInt32(' . $var . ')'; + return $this->_param($this->_paramIndex); + } default: return $var; } } - if (is_array($var)) { - foreach ($var as $index => $value) { + if (is_array($var)) + { + foreach ($var as $index => $value) + { $var[$index] = $this->_formatVar($value); } return $var; } - if (is_object($var)) { - $this->_paramIndex ++; - switch (get_class($var)) { + if (is_object($var)) + { + $this->_paramIndex++; + switch (get_class($var)) + { case "MongoId": $this->_phpParams[$this->_paramIndex] = 'new MongoId("' . $var->__toString() . '")'; return $this->_param($this->_paramIndex); - case "MongoInt32": - $this->_phpParams[$this->_paramIndex] = 'new MongoInt32(' . $var->__toString() . ')'; + case "MongoInt32": + $this->_phpParams[$this->_paramIndex] = 'new MongoInt32(' . $var->__toString() . ')'; return $this->_param($this->_paramIndex); - case "MongoInt64": - $this->_phpParams[$this->_paramIndex] = 'new MongoInt64(' . $var->__toString() . ')'; + case "MongoInt64": + $this->_phpParams[$this->_paramIndex] = 'new MongoInt64(' . $var->__toString() . ')'; return $this->_param($this->_paramIndex); case "MongoDate": $this->_phpParams[$this->_paramIndex] = 'new MongoDate(' . $var->sec . ', ' . $var->usec . ')'; @@ -158,69 +186,75 @@ private function _formatVar($var) { $this->_phpParams[$this->_paramIndex] = 'new MongoCode("' . addcslashes($var->code, '"') . '", ' . var_export($var->scope, true) . ')'; return $this->_param($this->_paramIndex); default: - if (method_exists($var, "__toString")) { + if (method_exists($var, "__toString")) + { return $var->__toString(); } } } return $var; - } - - private function _formatVarAsJSON($var, $jsonService) { - if (is_scalar($var) || is_null($var)) { - switch (gettype($var)) { + } + + private function _formatVarAsJSON($var, $jsonService) + { + if (is_scalar($var) || is_null($var)) + { + switch (gettype($var)) + { case "integer": - $this->_paramIndex ++; + $this->_paramIndex++; $this->_jsonParams[$this->_paramIndex] = 'NumberInt(' . $var . ')'; return $this->_param($this->_paramIndex); default: return $var; } } - if (is_array($var)) { - foreach ($var as $index => $value) { + if (is_array($var)) + { + foreach ($var as $index => $value) + { $var[$index] = $this->_formatVarAsJSON($value, $jsonService); } return $var; } - if (is_object($var)) { - $this->_paramIndex ++; - switch (get_class($var)) { + if (is_object($var)) + { + $this->_paramIndex++; + switch (get_class($var)) + { case "MongoId": $this->_jsonParams[$this->_paramIndex] = 'ObjectId("' . $var->__toString() . '")'; return $this->_param($this->_paramIndex); - case "MongoInt32": - $this->_jsonParams[$this->_paramIndex] = 'NumberInt(' . $var->__toString() . ')'; - return $this->_param($this->_paramIndex); - case "MongoInt64": - $this->_jsonParams[$this->_paramIndex] = 'NumberLong(' . $var->__toString() . ')'; + case "MongoInt32": + $this->_jsonParams[$this->_paramIndex] = 'NumberInt(' . $var->__toString() . ')'; + return $this->_param($this->_paramIndex); + case "MongoInt64": + $this->_jsonParams[$this->_paramIndex] = 'NumberLong(' . $var->__toString() . ')'; return $this->_param($this->_paramIndex); case "MongoDate": $timezone = @date_default_timezone_get(); date_default_timezone_set("UTC"); - $this->_jsonParams[$this->_paramIndex] = "ISODate(\"" . date("Y-m-d", $var->sec) . "T" . date("H:i:s.", $var->sec) . ($var->usec/1000) . "Z\")"; + $this->_jsonParams[$this->_paramIndex] = "ISODate(\"" . date("Y-m-d", $var->sec) . "T" . date("H:i:s.", $var->sec) . ($var->usec / 1000) . "Z\")"; date_default_timezone_set($timezone); return $this->_param($this->_paramIndex); case "MongoTimestamp": - $this->_jsonParams[$this->_paramIndex] = call_user_func($jsonService, array( - "t" => $var->inc * 1000, - "i" => $var->sec - )); + $this->_jsonParams[$this->_paramIndex] = call_user_func($jsonService, array("t" => $var->inc * 1000, "i" => $var->sec)); return $this->_param($this->_paramIndex); case "MongoMinKey": - $this->_jsonParams[$this->_paramIndex] = call_user_func($jsonService, array( '$minKey' => 1 )); + $this->_jsonParams[$this->_paramIndex] = call_user_func($jsonService, array('$minKey' => 1)); return $this->_param($this->_paramIndex); case "MongoMaxKey": - $this->_jsonParams[$this->_paramIndex] = call_user_func($jsonService, array( '$minKey' => 1 )); + $this->_jsonParams[$this->_paramIndex] = call_user_func($jsonService, array('$minKey' => 1)); return $this->_param($this->_paramIndex); case "MongoCode": $this->_jsonParams[$this->_paramIndex] = $var->__toString(); return $this->_param($this->_paramIndex); default: - if (method_exists($var, "__toString")) { - return $var->__toString(); - } - return ''; + if (method_exists($var, "__toString")) + { + return $var->__toString(); + } + return ''; } } } diff --git a/app/configs/rplugin.php b/app/configs/rplugin.php index 1ee58d7..d1f9fbc 100644 --- a/app/configs/rplugin.php +++ b/app/configs/rplugin.php @@ -1,7 +1,6 @@ - \ No newline at end of file diff --git a/app/controllers/admin.php b/app/controllers/admin.php index 1f2540c..92e5b1a 100644 --- a/app/controllers/admin.php +++ b/app/controllers/admin.php @@ -1,94 +1,110 @@ -topUrl = $this->path("admin.top"); - $this->leftUrl = $this->path("admin.dbs"); - $this->rightUrl = $this->path("server.index"); - - $this->display(); - } - - /** top frame **/ - public function doTop() { - $this->logoutUrl = $this->path("logout.index"); - $this->admin = $this->_admin->username(); - - $this->servers = $this->_admin->servers(); - $this->serverIndex = $this->_admin->hostIndex(); - - $isMasterRet = null; - try { - $isMasterRet = $this->_mongo->selectDB($this->_admin->defaultDb())->command(array( "isMaster" => 1 )); - if ($isMasterRet["ok"]) { - $this->isMaster = $isMasterRet["ismaster"]; - } - else { - $this->isMaster = true; - } - } catch (MongoCursorException $e) { - $this->isMaster = null; - } - - $this->display(); - } - - /** show dbs in left frame **/ - public function doDbs() { - $dbs = $this->_server->listDbs(); - $this->dbs = array_values(rock_array_sort($dbs["databases"], "name")); - $this->baseUrl = $this->path("admin.dbs"); - $this->tableUrl = $this->path("collection.index"); - $this->showDbSelector = false; - - //add collection count - foreach ($this->dbs as $index => $db) { - $collectionCount = count(MDb::listCollections($this->_mongo->selectDB($db["name"]))); - $db["collectionCount"] = $collectionCount; - if (isset($db["sizeOnDisk"])) { - $db["size"] = round($db["sizeOnDisk"]/1024/1024, 2);//M - } - $this->dbs[$index] = $db; - } - - //current db - $db = x("db"); - - $this->tables = array(); - if ($db) { - $mongodb = $this->_mongo->selectDB($db); - $tables = MDb::listCollections($mongodb); - foreach ($tables as $table) { - $this->tables[$table->getName()] = $table->count(); - } - } - $this->display(); - } - - /** about project and us **/ - public function doAbout() { - $this->display(); - } - - /** change current host **/ - public function doChangeHost() { - $index = xi("index"); - MUser::userInSession()->changeHost($index); - $this->redirect("admin.index", array( "host" => $index )); - } - - /** - * change language of UI interface - * - */ - public function doChangeLang() { - setcookie("ROCK_LANG", x("lang"), time() + 365 * 86400); - header("location:index.php"); - } -} - - +topUrl = $this->path("admin.top"); + $this->leftUrl = $this->path("admin.dbs"); + $this->rightUrl = $this->path("server.index"); + + $this->display(); + } + + /** top frame **/ + public function doTop() + { + $this->logoutUrl = $this->path("logout.index"); + $this->admin = $this->_admin->username(); + + $this->servers = $this->_admin->servers(); + $this->serverIndex = $this->_admin->hostIndex(); + + $isMasterRet = null; + try + { + $isMasterRet = $this->_mongo->selectDB($this->_admin->defaultDb())->command(array("isMaster" => 1)); + if ($isMasterRet["ok"]) + { + $this->isMaster = $isMasterRet["ismaster"]; + } + else + { + $this->isMaster = true; + } + } + catch (MongoCursorException $e) + { + $this->isMaster = null; + } + + $this->display(); + } + + /** show dbs in left frame **/ + public function doDbs() + { + $dbs = $this->_server->listDbs(); + $this->dbs = array_values(rock_array_sort($dbs["databases"], "name")); + $this->baseUrl = $this->path("admin.dbs"); + $this->tableUrl = $this->path("collection.index"); + $this->showDbSelector = false; + + //add collection count + foreach ($this->dbs as $index => $db) + { + $collectionCount = count(MDb::listCollections($this->_mongo->selectDB($db["name"]))); + $db["collectionCount"] = $collectionCount; + if (isset($db["sizeOnDisk"])) + { + $db["size"] = round($db["sizeOnDisk"] / 1024 / 1024, 2); //M + } + $this->dbs[$index] = $db; + } + + //current db + $db = x("db"); + + $this->tables = array(); + if ($db) + { + $mongodb = $this->_mongo->selectDB($db); + $tables = MDb::listCollections($mongodb); + foreach ($tables as $table) + { + $this->tables[$table->getName()] = $table->count(); + } + } + $this->display(); + } + + /** about project and us **/ + public function doAbout() + { + $this->display(); + } + + /** change current host **/ + public function doChangeHost() + { + $index = xi("index"); + MUser::userInSession()->changeHost($index); + $this->redirect("admin.index", array("host" => $index)); + } + + /** + * change language of UI interface + * + */ + public function doChangeLang() + { + setcookie("ROCK_LANG", x("lang"), time() + 365 * 86400); + header("location:index.php"); + } +} + + ?> \ No newline at end of file diff --git a/app/controllers/collection.php b/app/controllers/collection.php index 3c454bd..16f7f68 100644 --- a/app/controllers/collection.php +++ b/app/controllers/collection.php @@ -4,85 +4,94 @@ /** * collection controller - * + * * You should always input these parameters: * - db * - collection * to call the actions. - * + * * @author iwind * */ -class CollectionController extends BaseController { +class CollectionController extends BaseController +{ /** * DB Name - * + * * @var string */ public $db; - + /** * Collection Name - * + * * @var string */ public $collection; - + /** * DB instance * * @var MongoDB */ protected $_mongodb; - - public function onBefore() { + + public function onBefore() + { parent::onBefore(); $this->db = xn("db"); $this->collection = xn("collection"); $this->_mongodb = $this->_mongo->selectDB($this->db); - } - + } + /** * load single record * */ - public function doRecord() { + public function doRecord() + { $id = rock_real_id(xn("id")); $format = xn("format"); - + $queryFields = x("query_fields"); $fields = array(); - if (!empty($queryFields)) { - foreach ($queryFields as $queryField) { + if (!empty($queryFields)) + { + foreach ($queryFields as $queryField) + { $fields[$queryField] = 1; } } - - $row = $this->_mongodb->selectCollection($this->collection)->findOne(array( "_id" => $id ), $fields); - if (empty($row)) { + + $row = $this->_mongodb->selectCollection($this->collection)->findOne(array("_id" => $id), $fields); + if (empty($row)) + { $this->_outputJson(array("code" => 300, "message" => "The record has been removed.")); } $exporter = new VarExportor($this->_mongodb, $row); $data = $exporter->export($format); $html = $this->_highlight($row, $format, true); - $this->_outputJson(array("code" => 200, "data" => $data, "html" => $html )); + $this->_outputJson(array("code" => 200, "data" => $data, "html" => $html)); } - + /** * switch format between array and json */ - public function doSwitchFormat() { + public function doSwitchFormat() + { $data = xn("data"); $format = x("format"); - + $ret = null; - if ($format == "json") {//to json + if ($format == "json") + { //to json $eval = new VarEval($data, "array", $this->_mongodb); $array = $eval->execute(); $exportor = new VarExportor($this->_mongodb, $array); $ret = json_unicode_to_utf8($exportor->export(MONGO_EXPORT_JSON)); } - else if ($format == "array") {//to array + else if ($format == "array") + { //to array $eval = new VarEval($data, "json", $this->_mongodb); $array = $eval->execute(); $exportor = new VarExportor($this->_mongodb, $array); @@ -90,94 +99,103 @@ public function doSwitchFormat() { } $this->_outputJson(array("code" => 200, "data" => $ret)); } - + /** show one collection **/ - public function doIndex() { + public function doIndex() + { $this->db = xn("db"); $this->collection = xn("collection"); - + //selected format last time $this->last_format = rock_cookie("rock_format", "json"); - + //write query to log $params = xn(); - if ($this->_logQuery && count($params) > 3) {//not only "action", "db" and "collection" + if ($this->_logQuery && count($params) > 3) + { //not only "action", "db" and "collection" $logDir = dirname(__ROOT__) . DS . "logs"; - if (is_writable($logDir)) { + if (is_writable($logDir)) + { $logFile = $this->_logFile($this->db, $this->collection); $fp = null; - if (!is_file($logFile)) { + if (!is_file($logFile)) + { $fp = fopen($logFile, "a+"); fwrite($fp, '' . "\n"); } - else { + else + { $fp = fopen($logFile, "a+"); } fwrite($fp, date("Y-m-d H:i:s") . "\n" . var_export($params, true) . "\n================\n"); fclose($fp); } } - + //information $db = $this->_mongo->selectDB($this->db); $info = MCollection::info($db, $this->collection); $this->canAddField = !$info["capped"]; - + //field and sort $fields = xn("field"); $orders = xn("order"); - if (empty($fields)) { - $fields = array( - ($info["capped"]) ? "\$natural": "_id", "", "", "" - ); - $orders = array( - "desc", "asc", "asc", "asc" - ); + if (empty($fields)) + { + $fields = array(($info["capped"]) ? "\$natural" : "_id", "", "", ""); + $orders = array("desc", "asc", "asc", "asc"); x("field", $fields); x("order", $orders); } - + //format $format = x("format"); - if (!$format) { + if (!$format) + { $format = $this->last_format; x("format", $format); - } + } //remember last format choice $this->last_format = $format; $this->_rememberFormat($format); - + //read fields from collection import("models.MCollection"); $this->nativeFields = MCollection::fields($db, $this->collection); $this->queryFields = x("query_fields"); - if (!is_array($this->queryFields)) { + if (!is_array($this->queryFields)) + { $this->queryFields = array(); } - + $this->indexFields = $db->selectCollection($this->collection)->getIndexInfo(); $this->recordsCount = $db->selectCollection($this->collection)->count(); - foreach ($this->indexFields as $index => $indexField) { + foreach ($this->indexFields as $index => $indexField) + { $this->indexFields[$index]["keystring"] = $this->_encodeJson($indexField["key"]); } - + $this->queryHints = x("query_hints"); - if (!is_array($this->queryHints)) { + if (!is_array($this->queryHints)) + { $this->queryHints = array(); } - + //new obj in modification $newobj = trim(xn("newobj")); - if (!$newobj) { - if ($format == "array") { + if (!$newobj) + { + if ($format == "array") + { x("newobj", 'array( \'$set\' => array ( //your attributes ) )'); } - else { + else + { x("newobj", '{ \'$set\': { //your attributes @@ -185,27 +203,32 @@ public function doIndex() { }'); } } - + //conditions $native = xn("criteria"); $criteria = $native; - if (empty($criteria)) { + if (empty($criteria)) + { $criteria = array(); - if ($format == "array") { + if ($format == "array") + { $native = "array(\n\t\n)"; } - else if ($format == "json") { + else if ($format == "json") + { $native = '{ -}'; +}'; } x("pagesize", 10); } - else { + else + { $row = null; $eval = new VarEval($criteria, $format, $db); $row = $eval->execute(); - if (!is_array($row)) { + if (!is_array($row)) + { $this->message = "Criteria must be a valid " . (($format == "json") ? "JSON object" : "array"); $this->jsonLink = "#"; $this->arrayLink = "#"; @@ -214,25 +237,29 @@ public function doIndex() { } $criteria = $row; } - + //remember criteria in cookie (may be replaced by query history some day) //setcookie("criteria_" . $this->db . "__" . $this->collection . "__" . $format, $native, time() + ); x("criteria", $native); import("lib.mongo.RQuery"); $query = new RQuery($this->_mongo, $this->db, $this->collection); $query->cond($criteria); - + //sort $realOrderedFields = array(); $realOrderedOrders = array(); - foreach ($fields as $index => $field) { - if (!empty($field)) { + foreach ($fields as $index => $field) + { + if (!empty($field)) + { $realOrderedFields[] = $field; - if ($orders[$index] == "asc") { + if ($orders[$index] == "asc") + { $realOrderedOrders[] = "asc"; $query->asc($field); } - else { + else + { $realOrderedOrders[] = "desc"; $query->desc($field); } @@ -240,52 +267,61 @@ public function doIndex() { } x("field", $realOrderedFields); x("order", $realOrderedOrders); - + //command $command = x("command"); - if (!$command) { + if (!$command) + { $command = "findAll"; x("command", $command); } $limit = xi("limit"); - if ($limit > 0) { + if ($limit > 0) + { $query->limit($limit); } $count = ($limit > 0 && $command == "findAll") ? $query->count(true) : $query->count(); - - switch ($command) { + + switch ($command) + { case "findAll": - if (!empty($this->queryFields)) { + if (!empty($this->queryFields)) + { $query->result($this->queryFields); } - if (!empty($this->queryHints)) { - foreach ($this->indexFields as $index) { - if (in_array($index["name"], $this->queryHints)) { + if (!empty($this->queryHints)) + { + foreach ($this->indexFields as $index) + { + if (in_array($index["name"], $this->queryHints)) + { $query->hint($index["key"]); } } } break; case "remove": - $microtime = microtime(true); + $microtime = microtime(true); $query->delete(); $this->cost = microtime(true) - $microtime; break; case "modify": - $microtime = microtime(true); + $microtime = microtime(true); $row = null; $newobj = xn("newobj"); $eval = new VarEval($newobj, $format, $db); $row = $eval->execute(); - if (is_array($row)) { + if (is_array($row)) + { $query->upsert($row); } $this->cost = microtime(true) - $microtime; break; } - + //construct links - if ($format == "json") { + if ($format == "json") + { $params = xn(); unset($params["newobj"]); $exportor = new VarExportor($db, $criteria); @@ -295,9 +331,10 @@ public function doIndex() { $params = xn(); unset($params["newobj"]); $params["format"] = "json"; - $this->jsonLink = $this->path($this->action(), $params); + $this->jsonLink = $this->path($this->action(), $params); } - else if ($format == "array") { + else if ($format == "array") + { $params = xn(); unset($params["newobj"]); $params["format"] = "array"; @@ -305,25 +342,29 @@ public function doIndex() { $params = xn(); unset($params["newobj"]); $params["format"] = "json"; - if (empty($criteria)) { + if (empty($criteria)) + { $params["criteria"] = "{\n \n}"; } - else { + else + { $exportor = new VarExportor($db, $criteria); $params["criteria"] = $exportor->export(MONGO_EXPORT_JSON); } - $this->jsonLink = $this->path($this->action(), $params); + $this->jsonLink = $this->path($this->action(), $params); } - - if ($command != "findAll") { + + if ($command != "findAll") + { $this->count = $count; $this->display(); return; } - + //pagination $pagesize = xi("pagesize"); - if ($pagesize < 1) { + if ($pagesize < 1) + { $pagesize = 10; } import("lib.page.RPageStyle1"); @@ -334,17 +375,20 @@ public function doIndex() { $this->page = $page; $query->offset($page->offset()); - if ($limit > 0) { + if ($limit > 0) + { $query->limit(min($limit, $page->size())); } - else { + else + { $query->limit($page->size()); } - - $microtime = microtime(true); + + $microtime = microtime(true); $this->rows = $query->findAll(true); $this->cost = microtime(true) - $microtime; - foreach ($this->rows as $index => $row) { + foreach ($this->rows as $index => $row) + { $native = $row; $exportor = new VarExportor($query->db(), $native); $row["text"] = $exportor->export($format); @@ -356,40 +400,41 @@ public function doIndex() { $row["can_refresh"] = isset($row["_id"]); $this->rows[$index] = $row; } - + $this->display(); } - + /** * output query history * */ - public function doQueryHistory() { + public function doQueryHistory() + { ob_clean(); - + $logs = array(); $criterias = array(); - if ($this->_logQuery) { + if ($this->_logQuery) + { $logFile = $this->_logFile(xn("db"), xn("collection")); $this->logs = array(); - if (is_file($logFile)) { + if (is_file($logFile)) + { $size = 10240; $fp = fopen($logFile, "r"); fseek($fp, -$size, SEEK_END); $text = fread($fp, $size); fclose($fp); - + preg_match_all("/(\\d+\\-\\d+\\-\\d+\\s+\\d+:\\d+:\\d+)\n(.+)(={10,})/sU", $text, $match); - - foreach ($match[1] as $k => $time) { + + foreach ($match[1] as $k => $time) + { $eval = new VarEval($match[2][$k]); $params = $eval->execute(); - if (!in_array($params["criteria"], $criterias)) { - $logs[] = array( - "time" => $time, - "params" => $params, - "query" => http_build_query($params) - ); + if (!in_array($params["criteria"], $criterias)) + { + $logs[] = array("time" => $time, "params" => $params, "query" => http_build_query($params)); $criterias[] = $params["criteria"]; } } @@ -399,41 +444,42 @@ public function doQueryHistory() { $this->display(); exit(); } - - + + /** explain query **/ - public function doExplainQuery() { + public function doExplainQuery() + { $this->db = x("db"); $this->collection = xn("collection"); - + //field and sort $fields = xn("field"); $orders = xn("order"); $format = xn("format"); - if (empty($fields)) { - $fields = array( - "_id", "", "", "" - ); - $orders = array( - "desc", "asc", "asc", "asc" - ); + if (empty($fields)) + { + $fields = array("_id", "", "", ""); + $orders = array("desc", "asc", "asc", "asc"); x("field", $fields); x("order", $orders); } - - + + //conditions $native = xn("criteria"); $criteria = $native; - if (empty($criteria)) { + if (empty($criteria)) + { $criteria = array(); $native = "array(\n\t\n)"; } - else { + else + { $row = null; $eval = new VarEval($criteria, $format, $this->_mongo->selectDB($this->db)); $row = $eval->execute(); - if (!is_array($row)) { + if (!is_array($row)) + { $this->error = "To explain a query, criteria must be an array."; $this->display(); return; @@ -445,136 +491,151 @@ public function doExplainQuery() { import("lib.mongo.RQuery"); $query = new RQuery($this->_mongo, $this->db, $this->collection); $query->cond($criteria); - + //sort - foreach ($fields as $index => $field) { - if (!empty($field)) { - if ($orders[$index] == "asc") { + foreach ($fields as $index => $field) + { + if (!empty($field)) + { + if ($orders[$index] == "asc") + { $query->asc($field); } - else { + else + { $query->desc($field); } } } - + //command $command = x("command"); - if (!$command) { + if (!$command) + { $command = "findAll"; x("command", $command); } - + $queryHints = x("query_hints"); - if (!empty($queryHints)) { + if (!empty($queryHints)) + { $db = $this->_mongo->selectDB($this->db); $indexes = $db->selectCollection($this->collection)->getIndexInfo(); - foreach ($indexes as $index) { - if (in_array($index["name"], $queryHints)) { + foreach ($indexes as $index) + { + if (in_array($index["name"], $queryHints)) + { $query->hint($index["key"]); } } } - + $cursor = $query->cursor(); $this->ret = $this->_highlight($cursor->explain(), "json"); $this->display(); } - + /** delete on row **/ - public function doDeleteRow() { + public function doDeleteRow() + { $this->db = x("db"); $this->collection = xn("collection"); - + import("lib.mongo.RQuery"); $query = new RQuery($this->_mongo, $this->db, $this->collection); $ret = $query->id(rock_real_id(x("id")))->delete(); - + $this->redirectUrl(xn("uri"), true); } - + /** create row **/ - public function doCreateRow() { + public function doCreateRow() + { $this->db = x("db"); $this->collection = xn("collection"); - + $id = rock_real_id(x("id")); - - import("lib.mongo.RQuery"); - + + import("lib.mongo.RQuery"); + //selected format last time $this->last_format = rock_cookie("rock_format", "json"); - + //if is duplicating ... - if (!$this->isPost() && $id) { + if (!$this->isPost() && $id) + { $query = new RQuery($this->_mongo, $this->db, $this->collection); $row = $query->id($id)->findOne(); - if (!empty($row)) { + if (!empty($row)) + { unset($row["_id"]); import("classes.VarExportor"); $export = new VarExportor($query->db(), $row); x("data", $export->export($this->last_format)); } } - + //initialize - if (!$this->isPost() && !x("data")) { + if (!$this->isPost() && !x("data")) + { x("data", ($this->last_format == "json") ? "{\n\t\n}" : "array(\n\n)"); } - + //try to deal with data - if ($this->isPost()) { + if ($this->isPost()) + { $format = x("format"); $this->last_format = $format; - + $data = xn("data"); - $data = str_replace(array( - "%{created_at}" - ), time(), $data); - + $data = str_replace(array("%{created_at}"), time(), $data); + $row = null; $eval = new VarEval($data, $format, $this->_mongo->selectDb($this->db)); $row = $eval->execute(); - if ($row === false || !is_array($row)) { + if ($row === false || !is_array($row)) + { $this->error = "Data must be a valid {$format}."; $this->display(); return; } - + $query = new RQuery($this->_mongo, $this->db, $this->collection); - try { + try + { $ret = $query->insert($row, true); - } catch (Exception $e) { + } + catch (Exception $e) + { $this->error = $e->getMessage(); $this->display(); return; } - + //remember format choice $this->_rememberFormat($format); - - $this->redirect("collection.index", array( - "db" => $this->db, - "collection" => $this->collection - ), true); + + $this->redirect("collection.index", array("db" => $this->db, "collection" => $this->collection), true); } - + $this->display(); } - + /** modify one row **/ - public function doModifyRow() { + public function doModifyRow() + { $this->db = xn("db"); $this->collection = xn("collection"); $id = rock_real_id(xn("id")); - + //selected format last time $this->last_format = rock_cookie("rock_format", "json"); - - import("lib.mongo.RQuery"); + + import("lib.mongo.RQuery"); $query = new RQuery($this->_mongo, $this->db, $this->collection); $this->row = $query->id($id)->findOne(); - if (empty($this->row)) { + if (empty($this->row)) + { $this->error = "Record is not found."; $this->display(); return; @@ -584,55 +645,65 @@ public function doModifyRow() { import("classes.VarExportor"); $export = new VarExportor($query->db(), $this->data); $this->data = $export->export($this->last_format); - if ($this->last_format == "json") { + if ($this->last_format == "json") + { $this->data = json_unicode_to_utf8($this->data); } - - if ($this->isPost()) { + + if ($this->isPost()) + { $this->data = xn("data"); $format = x("format"); $this->last_format = $format; - + $row = null; $eval = new VarEval($this->data, $format, $this->_mongo->selectDb($this->db)); $row = $eval->execute(); - if ($row === false || !is_array($row)) { + if ($row === false || !is_array($row)) + { $this->error = "Only valid {$format} is accepted."; $this->display(); return; } - + $query = new RQuery($this->_mongo, $this->db, $this->collection); $obj = $query->id($this->row["_id"])->find(); $oldAttrs = $obj->attrs(); $obj->setAttrs($row); - foreach ($oldAttrs as $oldAttr => $oldValue) { - if ($oldAttr == "_id") { + foreach ($oldAttrs as $oldAttr => $oldValue) + { + if ($oldAttr == "_id") + { continue; } - if (!array_key_exists($oldAttr, $row)) { + if (!array_key_exists($oldAttr, $row)) + { $obj->remove($oldAttr); } } - try { + try + { $obj->save(); - } catch (Exception $e) { + } + catch (Exception $e) + { $this->error = $e->getMessage(); $this->display(); return; } - + //remember format choice $this->_rememberFormat($format); - + $this->message = "Updated successfully."; } - + $this->display(); } - + /** download file in GridFS **/ - public function doDownloadFile() { + public function doDownloadFile() + { $this->db = xn("db"); $this->collection = xn("collection"); $this->id = xn("id"); @@ -643,10 +714,12 @@ public function doDownloadFile() { $extension = strtolower($fileinfo["extension"]); import("lib.mime.types", false); ob_end_clean(); - if (isset($mime_types[$extension])) { + if (isset($mime_types[$extension])) + { header("Content-Type:" . $mime_types[$extension]); } - else { + else + { header("Content-Type:text/plain"); } header("Content-Disposition: attachment; filename=" . $fileinfo["basename"]); @@ -654,307 +727,342 @@ public function doDownloadFile() { echo $file->getBytes(); exit; } - + /** clear rows in collection **/ - public function doClearRows() { + public function doClearRows() + { $this->db = x("db"); $this->collection = xn("collection"); - - import("lib.mongo.RQuery"); + + import("lib.mongo.RQuery"); $query = new RQuery($this->_mongo, $this->db, $this->collection); $query->delete(); - + echo ''; - - $this->redirect("collection.index", array( - "db" => $this->db, - "collection" => $this->collection - ), true); + + $this->redirect("collection.index", array("db" => $this->db, "collection" => $this->collection), true); } - + /** drop collection **/ - public function doRemoveCollection() { + public function doRemoveCollection() + { $this->db = x("db"); $this->collection = xn("collection"); $db = $this->_mongo->selectDB($this->db); $db->dropCollection($this->collection); $this->display(); } - + /** list collection indexes **/ - public function doCollectionIndexes() { + public function doCollectionIndexes() + { $this->db = x("db"); $this->collection = xn("collection"); $collection = $this->_mongo->selectCollection($this->_mongo->selectDB($this->db), $this->collection); $this->indexes = $collection->getIndexInfo(); - foreach ($this->indexes as $_index => $index) { + foreach ($this->indexes as $_index => $index) + { $index["data"] = $this->_highlight($index["key"], "json"); $this->indexes[$_index] = $index; } $this->display(); } - + /** drop a collection index **/ - public function doDeleteIndex() { + public function doDeleteIndex() + { $this->db = x("db"); $this->collection = xn("collection"); - + $db = $this->_mongo->selectDB($this->db); $collection = $this->_mongo->selectCollection($db, $this->collection); $indexes = $collection->getIndexInfo(); - foreach ($indexes as $index) { - if ($index["name"] == trim(xn("index"))) { + foreach ($indexes as $index) + { + if ($index["name"] == trim(xn("index"))) + { $ret = $db->command(array("deleteIndexes" => $collection->getName(), "index" => $index["name"])); break; } } - - $this->redirect("collection.collectionIndexes", array( - "db" => $this->db, - "collection" => $this->collection - )); + + $this->redirect("collection.collectionIndexes", array("db" => $this->db, "collection" => $this->collection)); } - + /** create a collection index **/ - public function doCreateIndex() { + public function doCreateIndex() + { $this->db = x("db"); $this->collection = xn("collection"); $this->nativeFields = MCollection::fields($this->_mongo->selectDB($this->db), $this->collection); - if ($this->isPost()) { + if ($this->isPost()) + { $db = $this->_mongo->selectDB($this->db); $collection = $this->_mongo->selectCollection($db, $this->collection); - + $fields = xn("field"); - if (!is_array($fields)) { + if (!is_array($fields)) + { $this->message = "Index contains one field at least."; $this->display(); return; } $orders = xn("order"); $attrs = array(); - foreach ($fields as $index => $field) { + foreach ($fields as $index => $field) + { $field = trim($field); - if (!empty($field)) { + if (!empty($field)) + { $attrs[$field] = ($orders[$index] == "asc") ? 1 : -1; } } - if (empty($attrs)) { + if (empty($attrs)) + { $this->message = "Index contains one field at least."; $this->display(); return; } - + //if is unique $options = array(); - if (x("is_unique")) { + if (x("is_unique")) + { $options["unique"] = 1; - if (x("drop_duplicate")) { + if (x("drop_duplicate")) + { $options["dropDups"] = 1; } } $options["background"] = 1; $options["safe"] = 1; - + //name $name = trim(xn("name")); - if (!empty($name)) { + if (!empty($name)) + { $options["name"] = $name; } $collection->ensureIndex($attrs, $options); - - $this->redirect("collection.collectionIndexes", array( - "db" => $this->db, - "collection" => $this->collection - )); + + $this->redirect("collection.collectionIndexes", array("db" => $this->db, "collection" => $this->collection)); } - + $this->display(); } - + /** collection statistics **/ - public function doCollectionStats() { + public function doCollectionStats() + { $this->db = x("db"); $this->collection = xn("collection"); $this->stats = array(); - + $db = $this->_mongo->selectDB($this->db); - $ret = $db->command(array( "collStats" => $this->collection )); - if ($ret["ok"]) { + $ret = $db->command(array("collStats" => $this->collection)); + if ($ret["ok"]) + { $this->stats = $ret; - foreach ($this->stats as $index => $stat) { - if (is_array($stat)) { + foreach ($this->stats as $index => $stat) + { + if (is_array($stat)) + { $this->stats[$index] = $this->_highlight($stat, "json"); } } } - + //top - $ret = $this->_mongo->selectDB("admin")->command(array( "top" => 1 )); + $ret = $this->_mongo->selectDB("admin")->command(array("top" => 1)); $this->top = array(); $namespace = $this->db . "." . $this->collection; - if ($ret["ok"] && !empty($ret["totals"][$namespace])) { + if ($ret["ok"] && !empty($ret["totals"][$namespace])) + { $this->top = $ret["totals"][$namespace]; - foreach ($this->top as $index => $value) { + foreach ($this->top as $index => $value) + { $this->top[$index] = $value["count"]; } } $this->display(); } - + /** validate collection **/ - public function doCollectionValidate() { + public function doCollectionValidate() + { $this->db = x("db"); $this->collection = xn("collection"); - + $db = $this->_mongo->selectDB($this->db); $this->ret = $this->_highlight($db->selectCollection($this->collection)->validate(), "json"); $this->display(); } - + /** rename collection **/ - public function doCollectionRename() { + public function doCollectionRename() + { $this->db = xn("db"); $this->collection = xn("collection"); $this->realName = $this->collection; - if ($this->isPost()) { + if ($this->isPost()) + { $oldname = trim(xn("oldname")); $newname = trim(xn("newname")); $removeExists = trim(xn("remove_exists")); - if ($newname === "") { + if ($newname === "") + { $this->error = "Please enter a new name."; $this->display(); return; } - if (!$removeExists) { + if (!$removeExists) + { //Is there a same name? $collections = MDb::listCollections($this->_mongo->selectDB($this->db)); - foreach ($collections as $collection) { - if ($collection->getName() == $newname) { + foreach ($collections as $collection) + { + if ($collection->getName() == $newname) + { $this->error = "There is already a '{$newname}' collection, you should drop it before renaming."; $this->display(); return; } } } - $this->ret = $this->_mongo->selectDB($this->db)->execute('function (coll, newname, dropExists) { db.getCollection(coll).renameCollection(newname, dropExists);}', array( $oldname, $newname, (bool)$removeExists )); - if ($this->ret["ok"]) { - $this->realName = $newname; - $this->message = "Operation success."; - } - else { - $this->error = "Operation failure"; - } + $this->ret = $this->_mongo->selectDB($this->db)->execute('function (coll, newname, dropExists) { db.getCollection(coll).renameCollection(newname, dropExists);}', array($oldname, $newname, (bool)$removeExists)); + if ($this->ret["ok"]) + { + $this->realName = $newname; + $this->message = "Operation success."; + } + else + { + $this->error = "Operation failure"; + } $this->ret_json = $this->_highlight($this->ret, "json"); } $this->display(); } - + /** collection properties **/ - public function doCollectionProps() { + public function doCollectionProps() + { $this->db = xn("db"); $this->collection = xn("collection"); - - $ret = $this->_mongo->selectDB($this->db)->command(array( "collStats" => $this->collection )); - - if (!$ret["ok"]) { + + $ret = $this->_mongo->selectDB($this->db)->command(array("collStats" => $this->collection)); + + if (!$ret["ok"]) + { exit("There is something wrong:{$ret['errmsg']}, please refresh the page to try again."); } $this->isCapped = 0; $this->size = 0; $this->max = 0; $options = $ret; - if (isset($options["capped"])) { + if (isset($options["capped"])) + { $this->isCapped = $options["capped"]; } - if (isset($options["size"])) { + if (isset($options["size"])) + { $this->size = $options["size"]; } - if (isset($options["max"])) { + if (isset($options["max"])) + { $this->max = $options["max"]; } - if ($this->isPost()) { + if ($this->isPost()) + { $this->isCapped = xi("is_capped"); $this->size = xi("size"); $this->max = xi("max"); - + //rename current collection $bkCollection = $this->collection . "_rockmongo_bk_" . uniqid(); - $this->ret = $this->_mongo->selectDB($this->db)->execute('function (coll, newname, dropExists) { db.getCollection(coll).renameCollection(newname, dropExists);}', array( $this->collection, $bkCollection, true )); - if (!$this->ret["ok"]) { + $this->ret = $this->_mongo->selectDB($this->db)->execute('function (coll, newname, dropExists) { db.getCollection(coll).renameCollection(newname, dropExists);}', array($this->collection, $bkCollection, true)); + if (!$this->ret["ok"]) + { $this->error = "There is something wrong:{$this->ret['errmsg']}, please refresh the page to try again."; $this->display(); return; } - + //create new collection $db = $this->_mongo->selectDB($this->db); $db->createCollection($this->collection, $this->isCapped, $this->size, $this->max); - + //copy data to new collection - if (!$this->_copyCollection($db, $bkCollection, $this->collection, true)) { + if (!$this->_copyCollection($db, $bkCollection, $this->collection, true)) + { //try to recover - $this->ret = $db->execute('function (coll, newname, dropExists) { db.getCollection(coll).renameCollection(newname, dropExists);}', array( $bkCollection, $this->collection, true )); - + $this->ret = $db->execute('function (coll, newname, dropExists) { db.getCollection(coll).renameCollection(newname, dropExists);}', array($bkCollection, $this->collection, true)); + $this->error = "There is something wrong:{$ret['errmsg']}, please refresh the page to try again."; $this->display(); return; } - + //drop current collection $db->dropCollection($bkCollection); } - + $this->display(); } - + /** duplicate collection **/ - public function doCollectionDuplicate() { + public function doCollectionDuplicate() + { $this->db = xn("db"); $this->collection = xn("collection"); - - if (!$this->isPost()) { + + if (!$this->isPost()) + { x("target", $this->collection . "_copy"); x("remove_target", 1); x("copy_indexes", 1); } - if ($this->isPost()) { + if ($this->isPost()) + { $target = trim(xn("target")); $removeTarget = x("remove_target"); $copyIndexes = x("copy_indexes"); - if ($target === "") { + if ($target === "") + { $this->error = "Please enter a valid target."; $this->display(); return; } $db = $this->_mongo->selectDB($this->db); - if ($removeTarget) { + if ($removeTarget) + { $db->selectCollection($target)->drop(); } $this->_copyCollection($db, $this->collection, $target, $copyIndexes); $this->message = "Collection duplicated successfully."; - } + } $this->display(); } - + /** transfer a collection **/ - public function doCollectionTransfer() { - $this->redirect("db.dbTransfer", array( - "db" => xn("db"), - "collection" => xn("collection") - )); + public function doCollectionTransfer() + { + $this->redirect("db.dbTransfer", array("db" => xn("db"), "collection" => xn("collection"))); } - + /** export a collection **/ - public function doCollectionExport() { - $this->redirect("db.dbExport", array( "db" => xn("db"), "collection" => xn("collection"), "can_download" => xn("can_download") )); + public function doCollectionExport() + { + $this->redirect("db.dbExport", array("db" => xn("db"), "collection" => xn("collection"), "can_download" => xn("can_download"))); } - + /** import a collection **/ - public function doCollectionImport() { - $this->redirect("db.dbImport", array( "db" => xn("db") )); - } + public function doCollectionImport() + { + $this->redirect("db.dbImport", array("db" => xn("db"))); + } } ?> \ No newline at end of file diff --git a/app/controllers/db.php b/app/controllers/db.php index e4c305b..edc4a01 100644 --- a/app/controllers/db.php +++ b/app/controllers/db.php @@ -1,502 +1,566 @@ -db = trim(xn("db")); - - $dbs = $this->_server->listDbs(); - $ret = array(); - foreach ($dbs["databases"] as $db) { - if ($db["name"] == $this->db) { - $ret = $db; - } - } - - //collections - $db = $this->_mongo->selectDB($this->db); - $collections = MDb::listCollections($db); - - $ret = array_merge($ret, $db->command(array("dbstats" => 1))); - $ret["diskSize"] = "-"; - if (isset($ret["sizeOnDisk"])) { - $ret["diskSize"] = $this->_formatBytes($ret["sizeOnDisk"]); - } - if(isset($ret["dataSize"])) { - $ret["dataSize"] = $this->_formatBytes($ret["dataSize"]); - } - if(isset($ret["storageSize"])) { - $ret["storageSize"] = $this->_formatBytes($ret["storageSize"]); - } - if(isset($ret["indexSize"])) { - $ret["indexSize"] = $this->_formatBytes($ret["indexSize"]); - } - - - $this->stats = array(); - $this->stats["Size"] = $ret["diskSize"]; - $this->stats["Is Empty?"] = $ret["empty"] ? "Yes" : "No"; - if (empty($collections)) { - $this->stats["Collections"] = count($collections) . " collections:"; - $this->stats["Collections"] .= "
No collections yet"; - } - else { - $key = "Collections
[path("db.dropDbCollections", array( "db" => $this->db )) . "\" onclick=\"return window.confirm('Are you sure to drop all collections in the db?')\">Drop All]
[path("clearDbCollections", array( "db" => $this->db )) . "\" onclick=\"return window.confirm('Are you sure to clear all records in all collections?')\">Clear All]"; - $this->stats[$key] = count($collections) . " collections:"; - foreach ($collections as $collection) { - $this->stats[$key] .= "
path("collection.index", array( "db" => $this->db, "collection" => $collection->getName())) . "\">" . $collection->getName() . ""; - } - } - if(isset($ret["objects"])) { - $this->stats["Objects"] = $ret["objects"]; - } - if(isset($ret["dataSize"])) { - $this->stats["Data Size"] = $ret["dataSize"]; - } - if(isset($ret["storageSize"])) { - $this->stats["Storage Size"] = $ret["storageSize"]; - } - if(isset($ret["numEvents"])) { - $this->stats["Extents"] = $ret["numExtents"]; - } - if(isset($ret["indexes"])) { - $this->stats["Indexes"] = $ret["indexes"]; - } - if(isset($ret["indexSize"])) { - $this->stats["Index Size"] = $ret["indexSize"]; - } - - $this->display(); - } - - /** transfer db collections from one server to another **/ - public function doDbTransfer() { - $this->db = xn("db"); - - $db = $this->_mongo->selectDB($this->db); - $this->collections = $db->listCollections(); - $this->servers = $this->_admin->servers(); - - $this->selectedCollections = array(); - if (!$this->isPost()) { - $this->selectedCollections[] = xn("collection"); - x("copy_indexes", 1); - $this->target_host = ""; - $this->target_port = 27017; - $this->target_auth = 0; - $this->target_username = ""; - $this->target_password = ""; - } - else { - $this->target_host = trim(xn("target_host")); - $this->target_port = xi("target_port"); - $this->target_auth = xi("target_auth"); - $this->target_username = trim(xn("target_username")); - $this->target_password = trim(xn("target_password")); - - $checkeds = xn("checked"); - if (is_array($checkeds)) { - $this->selectedCollections = array_keys($checkeds); - } - if (empty($checkeds)) { - $this->error = "Please select collections which you want to transfer."; - $this->display(); - return; - } - if (empty($this->target_host)) { - $this->error = "Target host must not be empty."; - $this->display(); - return; - } - $copyIndexes = xi("copy_indexes"); - /**if ($target === "") { - $this->error = "Please enter a valid database name."; - $this->display(); - return; - }**/ - - //start to transfer - $targetOptions = array(); - if ($this->target_auth) { +db = trim(xn("db")); + + $dbs = $this->_server->listDbs(); + $ret = array(); + foreach ($dbs["databases"] as $db) + { + if ($db["name"] == $this->db) + { + $ret = $db; + } + } + + //collections + $db = $this->_mongo->selectDB($this->db); + $collections = MDb::listCollections($db); + + $ret = array_merge($ret, $db->command(array("dbstats" => 1))); + $ret["diskSize"] = "-"; + if (isset($ret["sizeOnDisk"])) + { + $ret["diskSize"] = $this->_formatBytes($ret["sizeOnDisk"]); + } + if (isset($ret["dataSize"])) + { + $ret["dataSize"] = $this->_formatBytes($ret["dataSize"]); + } + if (isset($ret["storageSize"])) + { + $ret["storageSize"] = $this->_formatBytes($ret["storageSize"]); + } + if (isset($ret["indexSize"])) + { + $ret["indexSize"] = $this->_formatBytes($ret["indexSize"]); + } + + + $this->stats = array(); + $this->stats["Size"] = $ret["diskSize"]; + $this->stats["Is Empty?"] = $ret["empty"] ? "Yes" : "No"; + if (empty($collections)) + { + $this->stats["Collections"] = count($collections) . " collections:"; + $this->stats["Collections"] .= "
No collections yet"; + } + else + { + $key = "Collections
[path("db.dropDbCollections", array("db" => $this->db)) . "\" onclick=\"return window.confirm('Are you sure to drop all collections in the db?')\">Drop All]
[path("clearDbCollections", array("db" => $this->db)) . "\" onclick=\"return window.confirm('Are you sure to clear all records in all collections?')\">Clear All]"; + $this->stats[$key] = count($collections) . " collections:"; + foreach ($collections as $collection) + { + $this->stats[$key] .= "
path("collection.index", array("db" => $this->db, "collection" => $collection->getName())) . "\">" . $collection->getName() . ""; + } + } + if (isset($ret["objects"])) + { + $this->stats["Objects"] = $ret["objects"]; + } + if (isset($ret["dataSize"])) + { + $this->stats["Data Size"] = $ret["dataSize"]; + } + if (isset($ret["storageSize"])) + { + $this->stats["Storage Size"] = $ret["storageSize"]; + } + if (isset($ret["numEvents"])) + { + $this->stats["Extents"] = $ret["numExtents"]; + } + if (isset($ret["indexes"])) + { + $this->stats["Indexes"] = $ret["indexes"]; + } + if (isset($ret["indexSize"])) + { + $this->stats["Index Size"] = $ret["indexSize"]; + } + + $this->display(); + } + + /** transfer db collections from one server to another **/ + public function doDbTransfer() + { + $this->db = xn("db"); + + $db = $this->_mongo->selectDB($this->db); + $this->collections = $db->listCollections(); + $this->servers = $this->_admin->servers(); + + $this->selectedCollections = array(); + if (!$this->isPost()) + { + $this->selectedCollections[] = xn("collection"); + x("copy_indexes", 1); + $this->target_host = ""; + $this->target_port = 27017; + $this->target_auth = 0; + $this->target_username = ""; + $this->target_password = ""; + } + else + { + $this->target_host = trim(xn("target_host")); + $this->target_port = xi("target_port"); + $this->target_auth = xi("target_auth"); + $this->target_username = trim(xn("target_username")); + $this->target_password = trim(xn("target_password")); + + $checkeds = xn("checked"); + if (is_array($checkeds)) + { + $this->selectedCollections = array_keys($checkeds); + } + if (empty($checkeds)) + { + $this->error = "Please select collections which you want to transfer."; + $this->display(); + return; + } + if (empty($this->target_host)) + { + $this->error = "Target host must not be empty."; + $this->display(); + return; + } + $copyIndexes = xi("copy_indexes"); + /**if ($target === "") { + $this->error = "Please enter a valid database name."; + $this->display(); + return; + }**/ + + //start to transfer + $targetOptions = array(); + if ($this->target_auth) + { $targetOptions["username"] = $this->target_username; - $targetOptions["password"] = $this->target_password; - } - $targetConnection = new RMongo("mongodb://" . $this->target_host . ":" . $this->target_port, $targetOptions); - $targetDb = $targetConnection->selectDB($this->db); - if ($this->target_auth) { + $targetOptions["password"] = $this->target_password; + } + $targetConnection = new RMongo("mongodb://" . $this->target_host . ":" . $this->target_port, $targetOptions); + $targetDb = $targetConnection->selectDB($this->db); + if ($this->target_auth) + { // "authenticate" can only be used between 1.0.1 - 1.2.11 - if (RMongo::compareVersion("1.0.1") >= 0 && RMongo::compareVersion("1.2.11") < 0) { - $targetDb->authenticate($this->target_username, $this->target_password); - } - } - $errors = array(); - foreach ($this->selectedCollections as $collectionName) { - $ret = $targetDb->command(array( - "cloneCollection" => $this->db . "." . $collectionName, - "from" => $this->_server->uri(), - "copyIndexes" => (bool)$copyIndexes - )); - if (!$ret["ok"]) { - $errors[] = MMongo::readException($ret); - break; - } - } - if (!empty($errors)) { - $this->error = implode("
", $errors); - $this->display(); - return; - } - - $this->message = "All data were transfered to '{$this->target_host}' successfully."; - } - - $this->display(); - } - - /** export db **/ - public function doDbExport() { - $this->db = xn("db"); - - $db = $this->_mongo->selectDB($this->db); - $this->collections = MDb::listCollections($db); - $this->selectedCollections = array(); - if (!$this->isPost()) { - $this->selectedCollections[] = xn("collection"); - } - else { - $checkeds = xn("checked"); - $canDownload = xn("can_download"); - if (is_array($checkeds)) { - $this->selectedCollections = array_keys($checkeds); - } - - sort($this->selectedCollections); - - import("classes.VarExportor"); - $this->contents = ""; - $this->countRows = 0; - - //indexes - foreach ($this->selectedCollections as $collection) { - $collObj = $db->selectCollection($collection); - $infos = $collObj->getIndexInfo(); - foreach ($infos as $info) { - $options = array(); - if (isset($info["unique"])) { - $options["unique"] = $info["unique"]; - } - $exportor = new VarExportor($db, $info["key"]); - $exportor2 = new VarExportor($db, $options); - $this->contents .= "\n/** {$collection} indexes **/\ndb.getCollection(\"" . addslashes($collection) . "\").ensureIndex(" . $exportor->export(MONGO_EXPORT_JSON) . "," . $exportor2->export(MONGO_EXPORT_JSON) . ");\n"; - } - } - - //data - foreach ($this->selectedCollections as $collection) { - $cursor = $db->selectCollection($collection)->find(); - $this->contents .= "\n/** " . $collection . " records **/\n"; - foreach ($cursor as $one) { - $this->countRows ++; - $exportor = new VarExportor($db, $one); - $this->contents .= "db.getCollection(\"" . addslashes($collection) . "\").insert(" . $exportor->export(MONGO_EXPORT_JSON) . ");\n"; - unset($exportor); - } - unset($cursor); - } - if (x("can_download")) { - $prefix = "mongo-" . urlencode($this->db) . "-" . date("Ymd-His"); - - //gzip - if (x("gzip")) { - ob_end_clean(); - header("Content-type: application/x-gzip"); - header("Content-Disposition: attachment; filename=\"{$prefix}.gz\""); - echo gzcompress($this->contents, 9); - exit(); - } - else { - ob_end_clean(); - header("Content-type: application/octet-stream"); - header("Content-Disposition: attachment; filename=\"{$prefix}.js\""); - echo $this->contents; - exit(); - } - } - } - - $this->display(); - } - - /** import db **/ - public function doDbImport() { - $this->db = xn("db"); - - if ($this->isPost()) { - $format = x("format"); - if (!empty($_FILES["json"]["tmp_name"])) { - $tmp = $_FILES["json"]["tmp_name"]; - - //read file by it's format - $body = ""; - if (preg_match("/\\.gz$/", $_FILES["json"]["name"])) { - $body = gzuncompress(file_get_contents($tmp)); - } - else { - $body = file_get_contents($tmp); - } - - //check format - - $ret = array("ok" => 0); - if ($format == "js") { - $ret = $this->_mongo->selectDB($this->db)->execute('function (){ ' . $body . ' }'); - - if (!$ret["ok"]) { - $this->error = $ret["errmsg"]; - } - else { - $this->message = "All data import successfully."; - } - } - else { - $collection = trim(xn("collection")); - if ($collection === "") { - $this->error2 = "Please enter the collection name"; - } - else { - $lines = explode("\n", $body); - foreach ($lines as $line) { - $line = trim($line); - if ($line) { - $ret = $this->_mongo->selectDB($this->db)->execute('function (c, o){ o=eval("(" + o + ")"); db.getCollection(c).insert(o); }', array( $collection, $line )); - } - } - - - if (!$ret["ok"]) { - $this->error2 = $ret["errmsg"]; - } - else { - $this->message2 = "All data import successfully."; - } - } - } - - } - else { - if ($format == "js") { - $this->error = "Either no file input or file is too large to upload."; - } - else { - $this->error2 = "Either no file input or file is too large to upload."; - } - } - } - - $this->display(); - } - - /** db profiling **/ - public function doProfile() { - $this->db = xn("db"); - - import("lib.mongo.RQuery"); - import("lib.page.RPageStyle1"); - $query = new RQuery($this->_mongo, $this->db, "system.profile"); - $page = new RPageStyle1(); - $page->setTotal($query->count()); - $page->setSize(10); - $page->setAutoQuery(); - $this->page = $page; - - $this->rows = $query - ->offset($page->offset()) - ->limit($page->size()) - ->desc("ts") - ->findAll(); - foreach ($this->rows as $index => $row) { - $this->rows[$index]["text"] = $this->_highlight($row, "json"); - } - - $this->display(); - } - - /** change db profiling level **/ - public function doProfileLevel() { - $this->db = xn("db"); - - $db = $this->_mongo->selectDB($this->db); - $query1 = $db->execute("function (){ return db.getProfilingLevel(); }"); - $this->level = $query1["retval"]; - if (x("go") == "save_level") { - $level = xi("level"); - $slowms = xi("slowms"); - $db->execute("function(level,slowms) { db.setProfilingLevel(level,slowms); }", array($level, $slowms)); - $this->level = $level; - } - else { - x("slowms", 50); - } - $this->display(); - } - - /** clear profiling data **/ - public function doClearProfile() { - $this->db = xn("db"); - $db = $this->_mongo->selectDB($this->db); - - $query1 = $db->execute("function (){ return db.getProfilingLevel(); }"); - $oldLevel = $query1["retval"]; - $db->execute("function(level) { db.setProfilingLevel(level); }", array(0)); - $ret = $db->selectCollection("system.profile")->drop(); - $db->execute("function(level) { db.setProfilingLevel(level); }", array($oldLevel)); - - $this->redirect("db.profile", array( - "db" => $this->db - )); - } - - /** authentication **/ - public function doAuth() { - $this->db = xn("db"); - $db = $this->_mongo->selectDB($this->db); - - //users - $collection = $db->selectCollection("system.users"); - $cursor = $collection->find(); - $this->users= array(); - while($cursor->hasNext()) { - $this->users[] = $cursor->getNext(); - } - - $this->display(); - } - - /** delete user **/ - public function doDeleteUser() { - $this->db = xn("db"); - $db = $this->_mongo->selectDB($this->db); - - $db->execute("function (username){ db.removeUser(username); }", array(xn("user"))); - $this->redirect("db.auth", array( - "db" => $this->db - )); - } - - /** add user **/ - public function doAddUser() { - $this->db = xn("db"); - - if (!$this->isPost()) { - $this->display(); - return; - } - - $username = trim(xn("username")); - $password = trim(xn("password")); - $password2 = trim(xn("password2")); - if ($username == "") { - $this->error = "You must supply a username for user."; - $this->display(); - return; - } - if ($password == "") { - $this->error = "You must supply a password for user."; - $this->display(); - return; - } - if ($password != $password2) { - $this->error = "Passwords you typed twice is not same."; - $this->display(); - return; - } - $db = $this->_mongo->selectDB($this->db); - $db->execute("function (username, pass, readonly){ db.addUser(username, pass, readonly); }", array( - $username, - $password, - x("readonly") ? true : false - )); - - $this->redirect("auth", array( - "db" => $this->db - )); - } - - /** create new collection **/ - public function doNewCollection() { - $this->db = xn("db"); - $this->name = trim(xn("name")); - $this->isCapped = xi("is_capped"); - $this->size = xi("size"); - $this->max = xi("max"); - - if ($this->isPost()) { - $db = $this->_mongo->selectDB($this->db); - $db->createCollection($this->name, $this->isCapped, $this->size, $this->max); - $this->message = "New collection is created."; - - //add index - if (!$this->isCapped) { - $db->selectCollection($this->name)->ensureIndex(array( "_id" => 1 )); - } - } - - $this->display(); - } - - /** drop all collections in a db **/ - public function doDropDbCollections() { - $this->db = xn("db"); - $db = $this->_mongo->selectDB($this->db); - foreach ($db->listCollections() as $collection) { - $collection->drop(); - } - echo ''; - $this->redirect("db.index", array( "db" => $this->db ), true); - } - - /** clear all records in all collections **/ - public function doClearDbCollections() { - $this->db = xn("db"); - $db = $this->_mongo->selectDB($this->db); - foreach ($db->listCollections() as $collection) { - $collection->remove(); - } - echo ''; - $this->redirect("db.index", array( "db" => $this->db ), true); - } - - /** repair dataase **/ - public function doRepairDatabase() { - $this->db = xn("db"); - - $db = $this->_mongo->selectDB($this->db); - $ret = $db->command(array( "repairDatabase" => 1 )); - //$ret = $db->execute('function (){ return db.repairDatabase(); }'); //occure error in current version, we did not know why? - $this->ret = $this->_highlight($ret, "json"); - $this->display(); - } - - /** drop database **/ - public function doDropDatabase() { - $this->db = xn("db"); - - if (!x("confirm")) { - $this->display(); - return; - } - - $ret = $this->_mongo->dropDB($this->db); - $this->ret = $this->_highlight($ret, "json"); - $this->display("dropDatabaseResult"); - } -} - + if (RMongo::compareVersion("1.0.1") >= 0 && RMongo::compareVersion("1.2.11") < 0) + { + $targetDb->authenticate($this->target_username, $this->target_password); + } + } + $errors = array(); + foreach ($this->selectedCollections as $collectionName) + { + $ret = $targetDb->command(array("cloneCollection" => $this->db . "." . $collectionName, "from" => $this->_server->uri(), "copyIndexes" => (bool)$copyIndexes)); + if (!$ret["ok"]) + { + $errors[] = MMongo::readException($ret); + break; + } + } + if (!empty($errors)) + { + $this->error = implode("
", $errors); + $this->display(); + return; + } + + $this->message = "All data were transfered to '{$this->target_host}' successfully."; + } + + $this->display(); + } + + /** export db **/ + public function doDbExport() + { + $this->db = xn("db"); + + $db = $this->_mongo->selectDB($this->db); + $this->collections = MDb::listCollections($db); + $this->selectedCollections = array(); + if (!$this->isPost()) + { + $this->selectedCollections[] = xn("collection"); + } + else + { + $checkeds = xn("checked"); + $canDownload = xn("can_download"); + if (is_array($checkeds)) + { + $this->selectedCollections = array_keys($checkeds); + } + + sort($this->selectedCollections); + + import("classes.VarExportor"); + $this->contents = ""; + $this->countRows = 0; + + //indexes + foreach ($this->selectedCollections as $collection) + { + $collObj = $db->selectCollection($collection); + $infos = $collObj->getIndexInfo(); + foreach ($infos as $info) + { + $options = array(); + if (isset($info["unique"])) + { + $options["unique"] = $info["unique"]; + } + $exportor = new VarExportor($db, $info["key"]); + $exportor2 = new VarExportor($db, $options); + $this->contents .= "\n/** {$collection} indexes **/\ndb.getCollection(\"" . addslashes($collection) . "\").ensureIndex(" . $exportor->export(MONGO_EXPORT_JSON) . "," . $exportor2->export(MONGO_EXPORT_JSON) . ");\n"; + } + } + + //data + foreach ($this->selectedCollections as $collection) + { + $cursor = $db->selectCollection($collection)->find(); + $this->contents .= "\n/** " . $collection . " records **/\n"; + foreach ($cursor as $one) + { + $this->countRows++; + $exportor = new VarExportor($db, $one); + $this->contents .= "db.getCollection(\"" . addslashes($collection) . "\").insert(" . $exportor->export(MONGO_EXPORT_JSON) . ");\n"; + unset($exportor); + } + unset($cursor); + } + if (x("can_download")) + { + $prefix = "mongo-" . urlencode($this->db) . "-" . date("Ymd-His"); + + //gzip + if (x("gzip")) + { + ob_end_clean(); + header("Content-type: application/x-gzip"); + header("Content-Disposition: attachment; filename=\"{$prefix}.gz\""); + echo gzcompress($this->contents, 9); + exit(); + } + else + { + ob_end_clean(); + header("Content-type: application/octet-stream"); + header("Content-Disposition: attachment; filename=\"{$prefix}.js\""); + echo $this->contents; + exit(); + } + } + } + + $this->display(); + } + + /** import db **/ + public function doDbImport() + { + $this->db = xn("db"); + + if ($this->isPost()) + { + $format = x("format"); + if (!empty($_FILES["json"]["tmp_name"])) + { + $tmp = $_FILES["json"]["tmp_name"]; + + //read file by it's format + $body = ""; + if (preg_match("/\\.gz$/", $_FILES["json"]["name"])) + { + $body = gzuncompress(file_get_contents($tmp)); + } + else + { + $body = file_get_contents($tmp); + } + + //check format + + $ret = array("ok" => 0); + if ($format == "js") + { + $ret = $this->_mongo->selectDB($this->db)->execute('function (){ ' . $body . ' }'); + + if (!$ret["ok"]) + { + $this->error = $ret["errmsg"]; + } + else + { + $this->message = "All data import successfully."; + } + } + else + { + $collection = trim(xn("collection")); + if ($collection === "") + { + $this->error2 = "Please enter the collection name"; + } + else + { + $lines = explode("\n", $body); + foreach ($lines as $line) + { + $line = trim($line); + if ($line) + { + $ret = $this->_mongo->selectDB($this->db)->execute('function (c, o){ o=eval("(" + o + ")"); db.getCollection(c).insert(o); }', array($collection, $line)); + } + } + + + if (!$ret["ok"]) + { + $this->error2 = $ret["errmsg"]; + } + else + { + $this->message2 = "All data import successfully."; + } + } + } + + } + else + { + if ($format == "js") + { + $this->error = "Either no file input or file is too large to upload."; + } + else + { + $this->error2 = "Either no file input or file is too large to upload."; + } + } + } + + $this->display(); + } + + /** db profiling **/ + public function doProfile() + { + $this->db = xn("db"); + + import("lib.mongo.RQuery"); + import("lib.page.RPageStyle1"); + $query = new RQuery($this->_mongo, $this->db, "system.profile"); + $page = new RPageStyle1(); + $page->setTotal($query->count()); + $page->setSize(10); + $page->setAutoQuery(); + $this->page = $page; + + $this->rows = $query->offset($page->offset())->limit($page->size())->desc("ts")->findAll(); + foreach ($this->rows as $index => $row) + { + $this->rows[$index]["text"] = $this->_highlight($row, "json"); + } + + $this->display(); + } + + /** change db profiling level **/ + public function doProfileLevel() + { + $this->db = xn("db"); + + $db = $this->_mongo->selectDB($this->db); + $query1 = $db->execute("function (){ return db.getProfilingLevel(); }"); + $this->level = $query1["retval"]; + if (x("go") == "save_level") + { + $level = xi("level"); + $slowms = xi("slowms"); + $db->execute("function(level,slowms) { db.setProfilingLevel(level,slowms); }", array($level, $slowms)); + $this->level = $level; + } + else + { + x("slowms", 50); + } + $this->display(); + } + + /** clear profiling data **/ + public function doClearProfile() + { + $this->db = xn("db"); + $db = $this->_mongo->selectDB($this->db); + + $query1 = $db->execute("function (){ return db.getProfilingLevel(); }"); + $oldLevel = $query1["retval"]; + $db->execute("function(level) { db.setProfilingLevel(level); }", array(0)); + $ret = $db->selectCollection("system.profile")->drop(); + $db->execute("function(level) { db.setProfilingLevel(level); }", array($oldLevel)); + + $this->redirect("db.profile", array("db" => $this->db)); + } + + /** authentication **/ + public function doAuth() + { + $this->db = xn("db"); + $db = $this->_mongo->selectDB($this->db); + + //users + $collection = $db->selectCollection("system.users"); + $cursor = $collection->find(); + $this->users = array(); + while ($cursor->hasNext()) + { + $this->users[] = $cursor->getNext(); + } + + $this->display(); + } + + /** delete user **/ + public function doDeleteUser() + { + $this->db = xn("db"); + $db = $this->_mongo->selectDB($this->db); + + $db->execute("function (username){ db.removeUser(username); }", array(xn("user"))); + $this->redirect("db.auth", array("db" => $this->db)); + } + + /** add user **/ + public function doAddUser() + { + $this->db = xn("db"); + + if (!$this->isPost()) + { + $this->display(); + return; + } + + $username = trim(xn("username")); + $password = trim(xn("password")); + $password2 = trim(xn("password2")); + if ($username == "") + { + $this->error = "You must supply a username for user."; + $this->display(); + return; + } + if ($password == "") + { + $this->error = "You must supply a password for user."; + $this->display(); + return; + } + if ($password != $password2) + { + $this->error = "Passwords you typed twice is not same."; + $this->display(); + return; + } + $db = $this->_mongo->selectDB($this->db); + $db->execute("function (username, pass, readonly){ db.addUser(username, pass, readonly); }", array($username, $password, x("readonly") ? true : false)); + + $this->redirect("auth", array("db" => $this->db)); + } + + /** create new collection **/ + public function doNewCollection() + { + $this->db = xn("db"); + $this->name = trim(xn("name")); + $this->isCapped = xi("is_capped"); + $this->size = xi("size"); + $this->max = xi("max"); + + if ($this->isPost()) + { + $db = $this->_mongo->selectDB($this->db); + $db->createCollection($this->name, $this->isCapped, $this->size, $this->max); + $this->message = "New collection is created."; + + //add index + if (!$this->isCapped) + { + $db->selectCollection($this->name)->ensureIndex(array("_id" => 1)); + } + } + + $this->display(); + } + + /** drop all collections in a db **/ + public function doDropDbCollections() + { + $this->db = xn("db"); + $db = $this->_mongo->selectDB($this->db); + foreach ($db->listCollections() as $collection) + { + $collection->drop(); + } + echo ''; + $this->redirect("db.index", array("db" => $this->db), true); + } + + /** clear all records in all collections **/ + public function doClearDbCollections() + { + $this->db = xn("db"); + $db = $this->_mongo->selectDB($this->db); + foreach ($db->listCollections() as $collection) + { + $collection->remove(); + } + echo ''; + $this->redirect("db.index", array("db" => $this->db), true); + } + + /** repair dataase **/ + public function doRepairDatabase() + { + $this->db = xn("db"); + + $db = $this->_mongo->selectDB($this->db); + $ret = $db->command(array("repairDatabase" => 1)); + //$ret = $db->execute('function (){ return db.repairDatabase(); }'); //occure error in current version, we did not know why? + $this->ret = $this->_highlight($ret, "json"); + $this->display(); + } + + /** drop database **/ + public function doDropDatabase() + { + $this->db = xn("db"); + + if (!x("confirm")) + { + $this->display(); + return; + } + + $ret = $this->_mongo->dropDB($this->db); + $this->ret = $this->_highlight($ret, "json"); + $this->display("dropDatabaseResult"); + } +} + ?> \ No newline at end of file diff --git a/app/controllers/field.php b/app/controllers/field.php index b4f2223..3d9bd72 100644 --- a/app/controllers/field.php +++ b/app/controllers/field.php @@ -2,7 +2,8 @@ import("classes.BaseController"); -class FieldController extends BaseController { +class FieldController extends BaseController +{ public $db; public $collection; /** @@ -11,23 +12,26 @@ class FieldController extends BaseController { * @var MongoDB */ protected $_mongodb; - - function onBefore() { + + function onBefore() + { parent::onBefore(); $this->db = xn("db"); $this->collection = xn("collection"); $this->_mongodb = $this->_mongo->selectDB($this->db); } - + /** * remove a field */ - function doRemove() { + function doRemove() + { $db = $this->_mongo->selectDb($this->db); - + $field = xn("field"); $id = xn("id"); - if ($id) { + if ($id) + { $db->execute('function (collection, id, field) { var col = db.getCollection(collection); var obj = { @@ -35,9 +39,10 @@ function doRemove() { }; obj["$unset"][field] = 1; col.update({"_id":id}, obj, false, false); - }', array( $this->collection, rock_real_id($id), $field )); + }', array($this->collection, rock_real_id($id), $field)); } - else { + else + { $db->execute('function (collection, field) { var col = db.getCollection(collection); var obj = { @@ -45,20 +50,22 @@ function doRemove() { }; obj["$unset"][field] = 1; col.update({}, obj, false, true); - }', array( $this->collection, $field )); + }', array($this->collection, $field)); } exit(); } - + /** * set field value to NULL */ - function doClear() { + function doClear() + { $db = $this->_mongo->selectDb($this->db); - + $field = xn("field"); $id = xn("id"); - if ($id) { + if ($id) + { $db->execute('function (collection, id, field) { var col = db.getCollection(collection); var obj = { @@ -66,9 +73,10 @@ function doClear() { }; obj["$set"][field] = null; col.update({"_id":id}, obj, false, false); - }', array( $this->collection, rock_real_id($id), $field )); + }', array($this->collection, rock_real_id($id), $field)); } - else { + else + { $db->execute('function (collection, field) { var col = db.getCollection(collection); var obj = { @@ -76,23 +84,25 @@ function doClear() { }; obj["$set"][field] = null; col.update({}, obj, false, true); - }', array( $this->collection, $field )); + }', array($this->collection, $field)); } exit(); - } - + } + /** * rename a field */ - function doRename() { + function doRename() + { $db = $this->_mongo->selectDB($this->db); - + $field = xn("field"); $id = xn("id"); $newname = trim(xn("newname")); $keep = xn("keep"); - if ($newname === "") { - $this->_outputJson(array( "code" => 300, "message" => "New field name must not be empty")); + if ($newname === "") + { + $this->_outputJson(array("code" => 300, "message" => "New field name must not be empty")); } $ret = $db->execute('function (coll, field, newname, id, keep){ var cursor; @@ -115,58 +125,67 @@ function doRename() { db.getCollection(coll).update(row, newobj); } } - }', array($this->collection, $field, $newname, rock_real_id($id), $keep ? true:false)); - $this->_outputJson(array( "code" => 200 )); + }', array($this->collection, $field, $newname, rock_real_id($id), $keep ? true : false)); + $this->_outputJson(array("code" => 200)); } - + /** * create new field */ - function doNew() { + function doNew() + { $db = $this->_mongo->selectDB($this->db); - + $id = xn("id"); $newname = trim(xn("newname")); $keep = xn("keep"); $dataType = xn("data_type"); $value = xn("value"); $boolValue = xn("bool_value"); - $integerValue = xn("integer_value"); + $integerValue = xn("integer_value"); $longValue = xn("long_value"); $doubleValue = xn("double_value"); $mixedValue = xn("mixed_value"); $format = x("format"); - + $this->_rememberFormat($format); - - if ($newname === "") { - $this->_outputJson(array( "code" => 300, "message" => "New field name must not be empty")); + + if ($newname === "") + { + $this->_outputJson(array("code" => 300, "message" => "New field name must not be empty")); } - + $realValue = null; - try { + try + { $realValue = $this->_convertValue($this->_mongodb, $dataType, $format, $value, $integerValue, $longValue, $doubleValue, $boolValue, $mixedValue); - } catch (Exception $e) { - $this->_outputJson(array( "code" => 400, "message" => $e->getMessage())); - } - - $fieldType = ""; - if ($dataType == "integer") { - $fieldType = "integer"; - } else if ($dataType == "long") { - $fieldType = "long"; - } - - if (!$keep) { - if ($id) { - $db->selectCollection($this->collection)->update(array( - "_id" => rock_real_id($id) - ), array( '$set' => array( $newname => $realValue ) )); + } + catch (Exception $e) + { + $this->_outputJson(array("code" => 400, "message" => $e->getMessage())); + } + + $fieldType = ""; + if ($dataType == "integer") + { + $fieldType = "integer"; + } + else if ($dataType == "long") + { + $fieldType = "long"; + } + + if (!$keep) + { + if ($id) + { + $db->selectCollection($this->collection)->update(array("_id" => rock_real_id($id)), array('$set' => array($newname => $realValue))); } - else { - $db->selectCollection($this->collection)->update(array(), array( '$set' => array( $newname => $realValue ) ), array( "multiple" => 1 )); + else + { + $db->selectCollection($this->collection)->update(array(), array('$set' => array($newname => $realValue)), array("multiple" => 1)); } - $this->_outputJson(array( "code" => 200 )); + $this->_outputJson(array("code" => 200)); } $ret = $db->execute('function (coll, newname, fieldType, value, id, keep){ if (typeof(value) != "object") { @@ -199,34 +218,39 @@ function doNew() { db.getCollection(coll).update(row, newobj); } } - }', array($this->collection, $newname, $fieldType, $realValue, rock_real_id($id), $keep ? true:false)); - if ($ret["ok"]) { - $this->_outputJson(array( "code" => 200 )); + }', array($this->collection, $newname, $fieldType, $realValue, rock_real_id($id), $keep ? true : false)); + if ($ret["ok"]) + { + $this->_outputJson(array("code" => 200)); } - else { - $this->_outputJson(array( "code" => 500, "message" => $ret["errmsg"] )); + else + { + $this->_outputJson(array("code" => 500, "message" => $ret["errmsg"])); } - } - + } + /** * load field data * */ - function doLoad() { + function doLoad() + { $collection = $this->_mongodb->selectCollection($this->collection); $id = xn("id"); $field = xn("field"); $type = "integer"; $data = null; - if ($id) { - $one = $collection->findOne(array( "_id" => rock_real_id($id) ));//not select field, because there is a bug in list, such as "list.0" + if ($id) + { + $one = $collection->findOne(array("_id" => rock_real_id($id))); //not select field, because there is a bug in list, such as "list.0" $data = rock_array_get($one, $field); - switch (gettype($data)) { + switch (gettype($data)) + { case "boolean": $type = "boolean"; break; case "integer": - $type = "integer"; + $type = "integer"; break; case "long": $type = "long"; @@ -240,11 +264,14 @@ function doLoad() { break; case "array": case "object": - // int64 is returned as object (Kyryl Bilokurov ) - if (get_class($data) == "MongoInt64") { - $type = "long"; - } else { - $type = "mixed"; + // int64 is returned as object (Kyryl Bilokurov ) + if (get_class($data) == "MongoInt64") + { + $type = "long"; + } + else + { + $type = "mixed"; } break; case "resource": @@ -258,57 +285,61 @@ function doLoad() { $exporter = new VarExportor($this->_mongodb, $data); $format = rock_cookie("rock_format", "json"); $represent = $exporter->export($format); - if ($format == "json") { + if ($format == "json") + { $represent = json_unicode_to_utf8($represent); } - $this->_outputJson(array( - "code" => 200, - "type" => $type, - // long requires special handling (Kyryl Bilokurov ) - "value" => ($type=="long") ? $data->__toString() : $data, - "represent" => $represent, - "format" => $format - )); + $this->_outputJson(array("code" => 200, "type" => $type, // long requires special handling (Kyryl Bilokurov ) + "value" => ($type == "long") ? $data->__toString() : $data, "represent" => $represent, "format" => $format)); } - + /** * update value for a field */ - function doUpdate() { + function doUpdate() + { $db = $this->_mongo->selectDB($this->db); - + $id = xn("id"); $newname = trim(xn("newname")); $dataType = xn("data_type"); $value = xn("value"); $boolValue = xn("bool_value"); - $integerValue = xn("integer_value"); + $integerValue = xn("integer_value"); $longValue = xn("long_value"); $doubleValue = xn("double_value"); $mixedValue = xn("mixed_value"); $format = xn("format"); - + $this->_rememberFormat($format); - - if ($newname === "") { - $this->_outputJson(array( "code" => 300, "message" => "New field name must not be empty")); + + if ($newname === "") + { + $this->_outputJson(array("code" => 300, "message" => "New field name must not be empty")); } - + $realValue = null; - try { + try + { $realValue = $this->_convertValue($this->_mongodb, $dataType, $format, $value, $integerValue, $longValue, $doubleValue, $boolValue, $mixedValue); - } catch (Exception $e) { - $this->_outputJson(array( "code" => 400, "message" => $e->getMessage())); } - + catch (Exception $e) + { + $this->_outputJson(array("code" => 400, "message" => $e->getMessage())); + } + $fieldType = ""; - if ($dataType=="integer") { - $fieldType = "integer"; - } else if ($dataType == "long") { - $fieldType = "long"; + if ($dataType == "integer") + { + $fieldType = "integer"; + } + else if ($dataType == "long") + { + $fieldType = "long"; } $ret = array(); - if ($id) { + if ($id) + { $ret = $db->execute('function (collection, id, field, fieldType, value) { var col = db.getCollection(collection); var obj = { @@ -327,7 +358,8 @@ function doUpdate() { col.update({ "_id": id }, obj, false, false); }', array($this->collection, rock_real_id($id), $newname, $fieldType, $realValue)); } - else { + else + { $ret = $db->execute('function (collection, field, fieldType, value) { var col = db.getCollection(collection); var obj = { @@ -346,85 +378,106 @@ function doUpdate() { col.update({}, obj, false, true); }', array($this->collection, $newname, $fieldType, $realValue)); } - if ($ret["ok"]) { - $this->_outputJson(array( "code" => 200 )); + if ($ret["ok"]) + { + $this->_outputJson(array("code" => 200)); } - else { - $this->_outputJson(array( "code" => 500, "message" => $ret["errmsg"] )); + else + { + $this->_outputJson(array("code" => 500, "message" => $ret["errmsg"])); } } - - function doIndexes() { + + function doIndexes() + { $field = xn("field"); $indexes = $this->_mongodb->selectCollection($this->collection)->getIndexInfo(); $ret = array(); - foreach ($indexes as $index) { - if (isset($index["key"][$field])) { - $ret[] = array( "name" => $index["name"], "key" => $this->_highlight($index["key"], MONGO_EXPORT_JSON)); + foreach ($indexes as $index) + { + if (isset($index["key"][$field])) + { + $ret[] = array("name" => $index["name"], "key" => $this->_highlight($index["key"], MONGO_EXPORT_JSON)); } } - $this->_outputJson(array( "code" => 200, "indexes" => $ret )); + $this->_outputJson(array("code" => 200, "indexes" => $ret)); } - - function doCreateIndex() { + + function doCreateIndex() + { $fields = xn("field"); - if (!is_array($fields)) { - $this->_outputJson(array( "code" => 300, "message" => "Index contains one field at least.")); + if (!is_array($fields)) + { + $this->_outputJson(array("code" => 300, "message" => "Index contains one field at least.")); } $orders = xn("order"); $attrs = array(); - foreach ($fields as $index => $field) { + foreach ($fields as $index => $field) + { $field = trim($field); - if (!empty($field)) { + if (!empty($field)) + { $attrs[$field] = ($orders[$index] == "asc") ? 1 : -1; } } - if (empty($attrs)) { - $this->_outputJson(array( "code" => 300, "message" => "Index contains one field at least.")); + if (empty($attrs)) + { + $this->_outputJson(array("code" => 300, "message" => "Index contains one field at least.")); } - + //if is unique $options = array(); - if (x("is_unique")) { + if (x("is_unique")) + { $options["unique"] = 1; - if (x("drop_duplicate")) { + if (x("drop_duplicate")) + { $options["dropDups"] = 1; } } $options["background"] = 1; $options["safe"] = 1; - + //name $name = trim(xn("name")); - if (!empty($name)) { + if (!empty($name)) + { $options["name"] = $name; } - + //check name $collection = $this->_mongodb->selectCollection($this->collection); $indexes = $collection->getIndexInfo(); - foreach ($indexes as $index) { - if ($index["name"] == $name) { - $this->_outputJson(array( "code" => 300, "message" => "The name \"{$name}\" is token by other index.")); + foreach ($indexes as $index) + { + if ($index["name"] == $name) + { + $this->_outputJson(array("code" => 300, "message" => "The name \"{$name}\" is token by other index.")); break; } - if ($attrs === $index["key"]) { - $this->_outputJson(array( "code" => 300, "message" => "The key on same fields already exists.")); + if ($attrs === $index["key"]) + { + $this->_outputJson(array("code" => 300, "message" => "The key on same fields already exists.")); break; } - } - - $ret = null; - try { + } + + $ret = null; + try + { $ret = $collection->ensureIndex($attrs, $options); - } catch (Exception $e) { - $this->_outputJson(array( "code" => 300, "message" => $e->getMessage())); } - if ($ret["ok"]) { - $this->_outputJson(array( "code" => 200)); + catch (Exception $e) + { + $this->_outputJson(array("code" => 300, "message" => $e->getMessage())); + } + if ($ret["ok"]) + { + $this->_outputJson(array("code" => 200)); } - else { - $this->_outputJson(array( "code" => 300, "message" => $ret["err"])); + else + { + $this->_outputJson(array("code" => 300, "message" => $ret["err"])); } } } diff --git a/app/controllers/index.php b/app/controllers/index.php index c3041e2..7d0d08d 100644 --- a/app/controllers/index.php +++ b/app/controllers/index.php @@ -2,9 +2,11 @@ import("classes.BaseController"); -class IndexController extends BaseController { +class IndexController extends BaseController +{ /** home **/ - public function doIndex() { + public function doIndex() + { $this->redirect("admin.index"); } } diff --git a/app/controllers/login.php b/app/controllers/login.php index b0d047e..9dd0cbe 100644 --- a/app/controllers/login.php +++ b/app/controllers/login.php @@ -1,61 +1,66 @@ -isAjax()) { - render_view("header"); - } - } - - /** - * login page and post - */ - public function doIndex() { - global $MONGO; - - $password = trim(xn("password")); - $this->username = trim(xn("username")); - $this->db = trim(xn("db")); - $this->hostIndex = xi("host"); - $this->languages = rock_load_languages(); - $this->expires = array( - 3 => "3 " . rock_lang("hours"), - 720 => "1 " . rock_lang("month"), - ); - $this->moreOptions = xi("more"); - - if ($this->isPost()) { - //server exists? - if (!isset($MONGO["servers"][$this->hostIndex])) { - $this->message = "Server does not exist"; - return; - } - - //authenticate - $server = MServer::serverWithIndex($this->hostIndex); - if (!$server->auth($this->username, $password, $this->db)) { - $this->message = rock_lang("can_not_auth"); - $this->display(); - return; - } - - //remember user - import("models.MUser"); - MUser::login($this->username, $password, $this->hostIndex, $this->db, xi("expire") * 3600); - - //remember lang - setcookie("ROCK_LANG", x("lang"), time() + 365 * 86400); - - //jump to admin page - $this->redirect("admin.index", array( "host" => $this->hostIndex )); - } - else { - $this->display(); - } - } -} - +isAjax()) + { + render_view("header"); + } + } + + /** + * login page and post + */ + public function doIndex() + { + global $MONGO; + + $password = trim(xn("password")); + $this->username = trim(xn("username")); + $this->db = trim(xn("db")); + $this->hostIndex = xi("host"); + $this->languages = rock_load_languages(); + $this->expires = array(3 => "3 " . rock_lang("hours"), 720 => "1 " . rock_lang("month"),); + $this->moreOptions = xi("more"); + + if ($this->isPost()) + { + //server exists? + if (!isset($MONGO["servers"][$this->hostIndex])) + { + $this->message = "Server does not exist"; + return; + } + + //authenticate + $server = MServer::serverWithIndex($this->hostIndex); + if (!$server->auth($this->username, $password, $this->db)) + { + $this->message = rock_lang("can_not_auth"); + $this->display(); + return; + } + + //remember user + import("models.MUser"); + MUser::login($this->username, $password, $this->hostIndex, $this->db, xi("expire") * 3600); + + //remember lang + setcookie("ROCK_LANG", x("lang"), time() + 365 * 86400); + + //jump to admin page + $this->redirect("admin.index", array("host" => $this->hostIndex)); + } + else + { + $this->display(); + } + } +} + ?> \ No newline at end of file diff --git a/app/controllers/logout.php b/app/controllers/logout.php index 71a9c26..23c9919 100644 --- a/app/controllers/logout.php +++ b/app/controllers/logout.php @@ -1,17 +1,20 @@ -redirect("login.index"); - } -} - +redirect("login.index"); + } +} + ?> \ No newline at end of file diff --git a/app/controllers/server.php b/app/controllers/server.php index 30b6986..bcf332d 100644 --- a/app/controllers/server.php +++ b/app/controllers/server.php @@ -1,271 +1,321 @@ -_mongo->selectDB("admin"); - - //command line - $query = $db->command(array("getCmdLineOpts" => 1)); - if (isset($query["argv"])) { - $this->commandLine = implode(" ", $query["argv"]); - } - else { - $this->commandLine = ""; - } - - //web server - $this->webServers = array(); - if (isset($_SERVER["SERVER_SOFTWARE"])) { - list($webServer) = explode(" ", $_SERVER["SERVER_SOFTWARE"]); - $this->webServers["Web server"] = $webServer; - } - $this->webServers["PHP version"] = "PHP " . PHP_VERSION; - $this->webServers["PHP extension"] = "mongo/" . RMongo::getVersion(); - - $this->directives = ini_get_all("mongo"); - - //build info - $ret = $db->command(array("buildinfo" => 1)); - $this->buildInfos = array(); - if ($ret["ok"]) { - unset($ret["ok"]); - $this->buildInfos = $ret; - } - - //connection - $this->connections = array( - "Host" => $this->_server->mongoHost(), - "Port" => $this->_server->mongoPort(), - "Username" => "******", - "Password" => "******" - ); - - $this->display(); - } - - /** Server Status **/ - public function doStatus() { - //status - $db = $this->_mongo->selectDB("admin"); - $ret = $db->command(array("serverStatus" => 1)); - $this->status = array(); - if ($ret["ok"]) { - unset($ret["ok"]); - $this->status = $ret; - foreach ($this->status as $index => $_status) { - $json = $this->_highlight($_status, "json"); - if ($index == "uptime") {//we convert it to days - if ($_status >= 86400) { - $json .= "s (" . ceil($_status/86400) . "days)"; - } - } - $this->status[$index] = $json; - } - } - - $this->display(); - } - - /** show databases **/ - public function doDatabases() { - $ret = $this->_server->listDbs(); - $this->dbs = $ret["databases"]; - foreach ($this->dbs as $index => $db) { - $mongodb = $this->_mongo->selectDB($db["name"]); - $ret = $mongodb->command(array("dbstats" => 1)); - $ret["collections"] = count(MDb::listCollections($mongodb)); - if (isset($db["sizeOnDisk"])) { - $ret["diskSize"] = $this->_formatBytes($db["sizeOnDisk"]); - $ret["dataSize"] = $this->_formatBytes($ret["dataSize"]); - } - else { - $ret["diskSize"] = "-"; - $ret["dataSize"] = "-"; - } - $ret["storageSize"] = $this->_formatBytes($ret["storageSize"]); - $ret["indexSize"] = $this->_formatBytes($ret["indexSize"]); - $this->dbs[$index] = array_merge($this->dbs[$index], $ret); - - } - $this->dbs = rock_array_sort($this->dbs, "name"); - $this->display(); - } - - /** execute command **/ - public function doCommand() { - $ret = $this->_server->listDbs(); - $this->dbs = $ret["databases"]; - - if (!$this->isPost()) { - x("command", json_format("{listCommands:1}")); - if (!x("db")) { - x("db", "admin"); - } - } - - if ($this->isPost()) { - $command = xn("command"); - $format = x("format"); - if ($format == "json") { - $command = $this->_decodeJson($command); - } - else { - $eval = new VarEval($command); - $command = $eval->execute(); - } - if (!is_array($command)) { - $this->message = "You should send a valid command"; - $this->display(); - return; - } - $this->ret = $this->_highlight($this->_mongo->selectDB(xn("db"))->command($command), $format); - } - $this->display(); - } - - /** execute code **/ - public function doExecute() { - $ret = $this->_server->listDbs(); - $this->dbs = $ret["databases"]; - if (!$this->isPost()) { - if (!x("db")) { - x("db", "admin"); - } - x("code", 'function () { - var plus = 1 + 2; - return plus; -}'); - } - if ($this->isPost()) { - $code = trim(xn("code")); - $arguments = xn("argument"); - if (!is_array($arguments)) { - $arguments = array(); - } - else { - $this->arguments = $arguments; - foreach ($arguments as $index => $argument) { - $argument = trim($argument); - $array = $this->_decodeJson($argument); - $arguments[$index] = $array; - } - } - $ret = $this->_mongo->selectDB(xn("db"))->execute($code, $arguments); - $this->ret = $this->_highlight($ret, "json"); - } - $this->display(); - } - - /** processlist **/ - public function doProcesslist() { - $query = $this->_mongo->selectDB("admin")->execute('function (){ - return db.$cmd.sys.inprog.find({ $all:1 }).next(); - }'); - - $this->progs = array(); - if ($query["ok"]) { - $this->progs = $query["retval"]["inprog"]; - } - foreach ($this->progs as $index => $prog) { - foreach ($prog as $key=>$value) { - if (is_array($value)) { - $this->progs[$index][$key] = $this->_highlight($value, "json"); - } - } - } - $this->display(); - } - - /** kill one operation in processlist **/ - public function doKillOp() { - $opid = xi("opid"); - $query = $this->_mongo->selectDB("admin")->execute('function (opid){ - return db.killOp(opid); - }', array( $opid )); - if ($query["ok"]) { - $this->redirect("server.processlist"); - } - $this->ret = $this->_highlight($query, "json"); - $this->display(); - } - - /** create databse **/ - public function doCreateDatabase() { - if ($this->isPost()) { - $name = trim(xn("name")); - if (empty($name)) { - $this->error = "Please input a valid database name."; - $this->display(); - return; - } - $this->message = "New database created."; - $this->_mongo->selectDb($name)->execute("function(){}"); - } - $this->display(); - } - - /** replication status **/ - public function doReplication() { - $ret = $this->_mongo->selectDB("local")->execute('function () { return db.getReplicationInfo(); }'); - $this->status = array(); - $status = isset($ret["retval"]) ? $ret["retval"] : array(); - if (isset($ret["retval"]["errmsg"])) { - $this->status["errmsg"] = $ret["retval"]["errmsg"]; - } - else { - foreach ($status as $param => $value) { - if ($param == "logSizeMB") { - $this->status["Configured oplog size"] = $value . "m"; - } - else if ($param == "timeDiff") { - $this->status["Log length start to end"] = $value . "secs (" . $status["timeDiffHours"] . "hrs)"; - } - else if ($param == "tFirst") { - $this->status["Oplog first event time"] = $value; - } - else if ($param == "tLast") { - $this->status["Oplog last event time"] = $value; - } - else if ($param == "now") { - $this->status["Now"] = $value; - } - } - } - - //slaves - $this->slaves = array(); - $query = $this->_mongo->selectDB("local")->selectCollection("slaves")->find(); - foreach ($query as $one) { - foreach ($one as $param=>$value) { - if ($param == "syncedTo") { - $one[$param] = date("Y-m-d H:i:s", $value->inc) . "." . $value->sec; - } - } - $this->slaves[] = $one; - } - - //masters - $this->masters = array(); - $query = $this->_mongo->selectDB("local")->selectCollection("sources")->find(); - foreach ($query as $one) { - foreach ($one as $param=>$value) { - if ($param == "syncedTo" || $param == "localLogTs") { - if ($value->inc > 0) { - $one[$param] = date("Y-m-d H:i:s", $value->inc) . "." . $value->sec; - } - } - } - $this->masters[] = $one; - } - - //me - $this->me = $this->_mongo->selectDB("local")->selectCollection("me")->findOne(); - - $this->display(); - } -} - +_mongo->selectDB("admin"); + + //command line + $query = $db->command(array("getCmdLineOpts" => 1)); + if (isset($query["argv"])) + { + $this->commandLine = implode(" ", $query["argv"]); + } + else + { + $this->commandLine = ""; + } + + //web server + $this->webServers = array(); + if (isset($_SERVER["SERVER_SOFTWARE"])) + { + list($webServer) = explode(" ", $_SERVER["SERVER_SOFTWARE"]); + $this->webServers["Web server"] = $webServer; + } + $this->webServers["PHP version"] = "PHP " . PHP_VERSION; + $this->webServers["PHP extension"] = "mongo/" . RMongo::getVersion(); + + $this->directives = ini_get_all("mongo"); + + //build info + $ret = $db->command(array("buildinfo" => 1)); + $this->buildInfos = array(); + if ($ret["ok"]) + { + unset($ret["ok"]); + $this->buildInfos = $ret; + } + + //connection + $this->connections = array("Host" => $this->_server->mongoHost(), "Port" => $this->_server->mongoPort(), "Username" => "******", "Password" => "******"); + + $this->display(); + } + + /** Server Status **/ + public function doStatus() + { + //status + $db = $this->_mongo->selectDB("admin"); + $ret = $db->command(array("serverStatus" => 1)); + $this->status = array(); + if ($ret["ok"]) + { + unset($ret["ok"]); + $this->status = $ret; + foreach ($this->status as $index => $_status) + { + $json = $this->_highlight($_status, "json"); + if ($index == "uptime") + { //we convert it to days + if ($_status >= 86400) + { + $json .= "s (" . ceil($_status / 86400) . "days)"; + } + } + $this->status[$index] = $json; + } + } + + $this->display(); + } + + /** show databases **/ + public function doDatabases() + { + $ret = $this->_server->listDbs(); + $this->dbs = $ret["databases"]; + foreach ($this->dbs as $index => $db) + { + $mongodb = $this->_mongo->selectDB($db["name"]); + $ret = $mongodb->command(array("dbstats" => 1)); + $ret["collections"] = count(MDb::listCollections($mongodb)); + if (isset($db["sizeOnDisk"])) + { + $ret["diskSize"] = $this->_formatBytes($db["sizeOnDisk"]); + $ret["dataSize"] = $this->_formatBytes($ret["dataSize"]); + } + else + { + $ret["diskSize"] = "-"; + $ret["dataSize"] = "-"; + } + $ret["storageSize"] = $this->_formatBytes($ret["storageSize"]); + $ret["indexSize"] = $this->_formatBytes($ret["indexSize"]); + $this->dbs[$index] = array_merge($this->dbs[$index], $ret); + + } + $this->dbs = rock_array_sort($this->dbs, "name"); + $this->display(); + } + + /** execute command **/ + public function doCommand() + { + $ret = $this->_server->listDbs(); + $this->dbs = $ret["databases"]; + + if (!$this->isPost()) + { + x("command", json_format("{listCommands:1}")); + if (!x("db")) + { + x("db", "admin"); + } + } + + if ($this->isPost()) + { + $command = xn("command"); + $format = x("format"); + if ($format == "json") + { + $command = $this->_decodeJson($command); + } + else + { + $eval = new VarEval($command); + $command = $eval->execute(); + } + if (!is_array($command)) + { + $this->message = "You should send a valid command"; + $this->display(); + return; + } + $this->ret = $this->_highlight($this->_mongo->selectDB(xn("db"))->command($command), $format); + } + $this->display(); + } + + /** execute code **/ + public function doExecute() + { + $ret = $this->_server->listDbs(); + $this->dbs = $ret["databases"]; + if (!$this->isPost()) + { + if (!x("db")) + { + x("db", "admin"); + } + x("code", 'function () { + var plus = 1 + 2; + return plus; +}'); + } + if ($this->isPost()) + { + $code = trim(xn("code")); + $arguments = xn("argument"); + if (!is_array($arguments)) + { + $arguments = array(); + } + else + { + $this->arguments = $arguments; + foreach ($arguments as $index => $argument) + { + $argument = trim($argument); + $array = $this->_decodeJson($argument); + $arguments[$index] = $array; + } + } + $ret = $this->_mongo->selectDB(xn("db"))->execute($code, $arguments); + $this->ret = $this->_highlight($ret, "json"); + } + $this->display(); + } + + /** processlist **/ + public function doProcesslist() + { + $query = $this->_mongo->selectDB("admin")->execute('function (){ + return db.$cmd.sys.inprog.find({ $all:1 }).next(); + }'); + + $this->progs = array(); + if ($query["ok"]) + { + $this->progs = $query["retval"]["inprog"]; + } + foreach ($this->progs as $index => $prog) + { + foreach ($prog as $key => $value) + { + if (is_array($value)) + { + $this->progs[$index][$key] = $this->_highlight($value, "json"); + } + } + } + $this->display(); + } + + /** kill one operation in processlist **/ + public function doKillOp() + { + $opid = xi("opid"); + $query = $this->_mongo->selectDB("admin")->execute('function (opid){ + return db.killOp(opid); + }', array($opid)); + if ($query["ok"]) + { + $this->redirect("server.processlist"); + } + $this->ret = $this->_highlight($query, "json"); + $this->display(); + } + + /** create databse **/ + public function doCreateDatabase() + { + if ($this->isPost()) + { + $name = trim(xn("name")); + if (empty($name)) + { + $this->error = "Please input a valid database name."; + $this->display(); + return; + } + $this->message = "New database created."; + $this->_mongo->selectDb($name)->execute("function(){}"); + } + $this->display(); + } + + /** replication status **/ + public function doReplication() + { + $ret = $this->_mongo->selectDB("local")->execute('function () { return db.getReplicationInfo(); }'); + $this->status = array(); + $status = isset($ret["retval"]) ? $ret["retval"] : array(); + if (isset($ret["retval"]["errmsg"])) + { + $this->status["errmsg"] = $ret["retval"]["errmsg"]; + } + else + { + foreach ($status as $param => $value) + { + if ($param == "logSizeMB") + { + $this->status["Configured oplog size"] = $value . "m"; + } + else if ($param == "timeDiff") + { + $this->status["Log length start to end"] = $value . "secs (" . $status["timeDiffHours"] . "hrs)"; + } + else if ($param == "tFirst") + { + $this->status["Oplog first event time"] = $value; + } + else if ($param == "tLast") + { + $this->status["Oplog last event time"] = $value; + } + else if ($param == "now") + { + $this->status["Now"] = $value; + } + } + } + + //slaves + $this->slaves = array(); + $query = $this->_mongo->selectDB("local")->selectCollection("slaves")->find(); + foreach ($query as $one) + { + foreach ($one as $param => $value) + { + if ($param == "syncedTo") + { + $one[$param] = date("Y-m-d H:i:s", $value->inc) . "." . $value->sec; + } + } + $this->slaves[] = $one; + } + + //masters + $this->masters = array(); + $query = $this->_mongo->selectDB("local")->selectCollection("sources")->find(); + foreach ($query as $one) + { + foreach ($one as $param => $value) + { + if ($param == "syncedTo" || $param == "localLogTs") + { + if ($value->inc > 0) + { + $one[$param] = date("Y-m-d H:i:s", $value->inc) . "." . $value->sec; + } + } + } + $this->masters[] = $one; + } + + //me + $this->me = $this->_mongo->selectDB("local")->selectCollection("me")->findOne(); + + $this->display(); + } +} + ?> \ No newline at end of file diff --git a/app/funcs/functions.php b/app/funcs/functions.php index 8c5172a..dbbac9e 100644 --- a/app/funcs/functions.php +++ b/app/funcs/functions.php @@ -4,9 +4,11 @@ * convert unicode in json to utf-8 * * @param string $json string to convert + * * @return string utf-8 string */ -function json_unicode_to_utf8($json){ +function json_unicode_to_utf8($json) +{ $json = preg_replace_callback("/\\\u([0-9a-f]{4})/", create_function('$match', ' $val = intval($match[1], 16); $c = ""; @@ -49,192 +51,205 @@ function json_unicode_to_utf8($json){ function json_format_html($json) { $json = json_unicode_to_utf8($json); - $tab = "  "; - $new_json = ""; - $indent_level = 0; - $in_string = false; - -/* - commented out by monk.e.boy 22nd May '08 - because my web server is PHP4, and - json_* are PHP5 functions... - - $json_obj = json_decode($json); - - if($json_obj === false) - return false; - - $json = json_encode($json_obj); -*/ - $len = strlen($json); - - for($c = 0; $c < $len; $c++) - { - $char = $json[$c]; - switch($char) - { - case '{': - case '[': - $char = "" . $char . "";//iwind - if(!$in_string) { - $new_json .= $char . "
" . str_repeat($tab, $indent_level+1); - $indent_level++; - } - else { - $new_json .= $char; - } - break; - case '}': - case ']': - $char = "" . $char . "";//iwind - if(!$in_string) - { - $indent_level--; - $new_json .= "
" . str_repeat($tab, $indent_level) . $char; - } - else - { - $new_json .= $char; - } - break; - case ',': - $char = "" . $char . "";//iwind - if(!$in_string) { - $new_json .= ",
" . str_repeat($tab, $indent_level); - } - else { - $new_json .= $char; - } - break; - case ':': - $char = "" . $char . "";//iwind - if($in_string) { - $new_json .= ":"; - } - else { - $new_json .= $char; - } - break; - case '"': - if($c > 0 && $json[$c-1] != '\\') { - $in_string = !$in_string; - if ($in_string) { - $new_json .= "" . $char; - } - else { - $new_json .= $char . ""; - } - break; - } - else if ($c == 0) { - $in_string = !$in_string; - $new_json .= "" . $char; - break; - } - default: - if (!$in_string && trim($char) !== "") { - $char = "" . $char . ""; - } - else { - if ($char == "&" || $char == "'" || $char == "\"" || $char == "<" || $char == ">") { - $char = htmlspecialchars($char); - } - } - $new_json .= $char; - break; - } - } - $new_json = preg_replace_callback("{(([\da-zA-Z_\.]+))+}", create_function('$match',' + $tab = "  "; + $new_json = ""; + $indent_level = 0; + $in_string = false; + + /* + commented out by monk.e.boy 22nd May '08 + because my web server is PHP4, and + json_* are PHP5 functions... + + $json_obj = json_decode($json); + + if($json_obj === false) + return false; + + $json = json_encode($json_obj); + */ + $len = strlen($json); + + for ($c = 0; $c < $len; $c++) + { + $char = $json[$c]; + switch ($char) + { + case '{': + case '[': + $char = "" . $char . ""; //iwind + if (!$in_string) + { + $new_json .= $char . "
" . str_repeat($tab, $indent_level + 1); + $indent_level++; + } + else + { + $new_json .= $char; + } + break; + case '}': + case ']': + $char = "" . $char . ""; //iwind + if (!$in_string) + { + $indent_level--; + $new_json .= "
" . str_repeat($tab, $indent_level) . $char; + } + else + { + $new_json .= $char; + } + break; + case ',': + $char = "" . $char . ""; //iwind + if (!$in_string) + { + $new_json .= ",
" . str_repeat($tab, $indent_level); + } + else + { + $new_json .= $char; + } + break; + case ':': + $char = "" . $char . ""; //iwind + if ($in_string) + { + $new_json .= ":"; + } + else + { + $new_json .= $char; + } + break; + case '"': + if ($c > 0 && $json[$c - 1] != '\\') + { + $in_string = !$in_string; + if ($in_string) + { + $new_json .= "" . $char; + } + else + { + $new_json .= $char . ""; + } + break; + } + else if ($c == 0) + { + $in_string = !$in_string; + $new_json .= "" . $char; + break; + } + default: + if (!$in_string && trim($char) !== "") + { + $char = "" . $char . ""; + } + else + { + if ($char == "&" || $char == "'" || $char == "\"" || $char == "<" || $char == ">") + { + $char = htmlspecialchars($char); + } + } + $new_json .= $char; + break; + } + } + $new_json = preg_replace_callback("{(([\da-zA-Z_\.]+))+}", create_function('$match', ' $string = str_replace("", "", $match[0]); $string = str_replace("", "", $string); return "" . $string . ""; '), $new_json); - return $new_json; + return $new_json; } function json_format($json) { - $tab = " "; - $new_json = ""; - $indent_level = 0; - $in_string = false; - -/* - commented out by monk.e.boy 22nd May '08 - because my web server is PHP4, and - json_* are PHP5 functions... - - $json_obj = json_decode($json); - - if($json_obj === false) - return false; - - $json = json_encode($json_obj); -*/ - $len = strlen($json); - - for($c = 0; $c < $len; $c++) - { - $char = $json[$c]; - switch($char) - { - case '{': - case '[': - if(!$in_string) - { - $new_json .= $char . "\n" . str_repeat($tab, $indent_level+1); - $indent_level++; - } - else - { - $new_json .= $char; - } - break; - case '}': - case ']': - if(!$in_string) - { - $indent_level--; - $new_json .= "\n" . str_repeat($tab, $indent_level) . $char; - } - else - { - $new_json .= $char; - } - break; - case ',': - if(!$in_string) - { - $new_json .= ",\n" . str_repeat($tab, $indent_level); - } - else - { - $new_json .= $char; - } - break; - case ':': - if(!$in_string) - { - $new_json .= ": "; - } - else - { - $new_json .= $char; - } - break; - case '"': - if($c > 0 && $json[$c-1] != '\\') - { - $in_string = !$in_string; - } - default: - $new_json .= $char; - break; - } - } - - return $new_json; + $tab = " "; + $new_json = ""; + $indent_level = 0; + $in_string = false; + + /* + commented out by monk.e.boy 22nd May '08 + because my web server is PHP4, and + json_* are PHP5 functions... + + $json_obj = json_decode($json); + + if($json_obj === false) + return false; + + $json = json_encode($json_obj); + */ + $len = strlen($json); + + for ($c = 0; $c < $len; $c++) + { + $char = $json[$c]; + switch ($char) + { + case '{': + case '[': + if (!$in_string) + { + $new_json .= $char . "\n" . str_repeat($tab, $indent_level + 1); + $indent_level++; + } + else + { + $new_json .= $char; + } + break; + case '}': + case ']': + if (!$in_string) + { + $indent_level--; + $new_json .= "\n" . str_repeat($tab, $indent_level) . $char; + } + else + { + $new_json .= $char; + } + break; + case ',': + if (!$in_string) + { + $new_json .= ",\n" . str_repeat($tab, $indent_level); + } + else + { + $new_json .= $char; + } + break; + case ':': + if (!$in_string) + { + $new_json .= ": "; + } + else + { + $new_json .= $char; + } + break; + case '"': + if ($c > 0 && $json[$c - 1] != '\\') + { + $in_string = !$in_string; + } + default: + $new_json .= $char; + break; + } + } + + return $new_json; } ?> \ No newline at end of file diff --git a/app/funcs/render.php b/app/funcs/render.php index 5ee5ca1..1b3bae8 100644 --- a/app/funcs/render.php +++ b/app/funcs/render.php @@ -3,11 +3,13 @@ * Render html tag beginning * * @param string $name tag name - * @param array $attrs tag attributes + * @param array $attrs tag attributes */ -function render_begin_tag($name, array $attrs = array()) { +function render_begin_tag($name, array $attrs = array()) +{ $tag = "<{$name}"; - foreach ($attrs as $key => $value) { + foreach ($attrs as $key => $value) + { $tag .= " {$key}=\"{$value}\""; } $tag .= ">"; @@ -18,15 +20,18 @@ function render_begin_tag($name, array $attrs = array()) { * Render select element * * @param string $name select name - * @param array $options data options + * @param array $options data options */ -function render_select($name, array $options, $selectedIndex, array $attrs = array()) { +function render_select($name, array $options, $selectedIndex, array $attrs = array()) +{ $attrs["name"] = $name; render_begin_tag("select", $attrs); $select = ""; - foreach ($options as $key => $value) { + foreach ($options as $key => $value) + { $select .= "