You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

531 lines
15 KiB

  1. <?php
  2. import("classes.BaseController");
  3. class DbController extends BaseController {
  4. /** database **/
  5. public function doIndex() {
  6. $this->db = trim(xn("db"));
  7. $dbs = $this->_server->listDbs();
  8. $ret = array();
  9. foreach ($dbs["databases"] as $db) {
  10. if ($db["name"] == $this->db) {
  11. $ret = $db;
  12. }
  13. }
  14. //collections
  15. $db = $this->_mongo->selectDB($this->db);
  16. $collections = MDb::listCollections($db);
  17. $ret = array_merge($ret, $db->command(array("dbstats" => 1)));
  18. $ret["diskSize"] = "-";
  19. if (isset($ret["sizeOnDisk"])) {
  20. $ret["diskSize"] = r_human_bytes($ret["sizeOnDisk"]);
  21. }
  22. if(isset($ret["dataSize"])) {
  23. $ret["dataSize"] = r_human_bytes($ret["dataSize"]);
  24. }
  25. if(isset($ret["storageSize"])) {
  26. $ret["storageSize"] = r_human_bytes($ret["storageSize"]);
  27. }
  28. if(isset($ret["indexSize"])) {
  29. $ret["indexSize"] = r_human_bytes($ret["indexSize"]);
  30. }
  31. $this->stats = array();
  32. $this->stats["Size"] = $ret["diskSize"];
  33. $this->stats["Is Empty?"] = $ret["empty"] ? "Yes" : "No";
  34. if (empty($collections)) {
  35. $this->stats["Collections"] = count($collections) . " collections:";
  36. $this->stats["Collections"] .= "<br/>No collections yet";
  37. }
  38. else {
  39. $key = "Collections<br/>[<a href=\"" . $this->path("db.dropDbCollections", array( "db" => $this->db )) . "\" onclick=\"return window.confirm('Are you sure to drop all collections in the db?')\"><u>Drop All</u></a>]<br/>[<a href=\"" . $this->path("clearDbCollections", array( "db" => $this->db )) . "\" onclick=\"return window.confirm('Are you sure to clear all records in all collections?')\"><u>Clear All</u></a>]";
  40. $this->stats[$key] = count($collections) . " collections:";
  41. foreach ($collections as $collection) {
  42. $this->stats[$key] .= "<br/><a href=\""
  43. . $this->path("collection.index", array( "db" => $this->db, "collection" => $collection->getName())) . "\">" . $collection->getName() . "</a>";
  44. }
  45. }
  46. if(isset($ret["objects"])) {
  47. $this->stats["Objects"] = $ret["objects"];
  48. }
  49. if (isset($ret["avgObjSize"])) {
  50. $this->stats["Avg Object Size"] = r_human_bytes($ret["avgObjSize"]);
  51. }
  52. if(isset($ret["dataSize"])) {
  53. $this->stats["Data Size"] = $ret["dataSize"];
  54. }
  55. if(isset($ret["storageSize"])) {
  56. $this->stats["Storage Size"] = $ret["storageSize"];
  57. }
  58. if(isset($ret["numExtents"])) {
  59. $this->stats["Extents"] = $ret["numExtents"];
  60. }
  61. if(isset($ret["indexes"])) {
  62. $this->stats["Indexes"] = $ret["indexes"];
  63. }
  64. if(isset($ret["indexSize"])) {
  65. $this->stats["Index Size"] = r_human_bytes($ret["indexSize"]);
  66. }
  67. if (isset($ret["fileSize"])) {
  68. $this->stats["Total File Size"] = r_human_bytes($ret["fileSize"]);
  69. }
  70. if (isset($ret["nsSizeMB"])) {
  71. $this->stats["Namespace Size"] = $ret["nsSizeMB"] . "m";
  72. }
  73. if (isset($ret["dataFileVersion"])) {
  74. $this->stats["Data File Version"] = $this->_highlight($ret["dataFileVersion"], "json");
  75. }
  76. if (isset($ret["extentFreeList"])) {
  77. $this->stats["Extent Free List"] = $this->_highlight($ret["extentFreeList"], "json");
  78. }
  79. $this->display();
  80. }
  81. /** transfer db collections from one server to another **/
  82. public function doDbTransfer() {
  83. $this->db = xn("db");
  84. $db = $this->_mongo->selectDB($this->db);
  85. $this->collections = $db->listCollections();
  86. $this->servers = $this->_admin->servers();
  87. $this->selectedCollections = array();
  88. if (!$this->isPost()) {
  89. $this->selectedCollections[] = xn("collection");
  90. x("copy_indexes", 1);
  91. $this->target_host = "";
  92. $this->target_sock = "";
  93. $this->target_port = 27017;
  94. $this->target_auth = 0;
  95. $this->target_username = "";
  96. $this->target_password = "";
  97. }
  98. else {
  99. $this->target_host = trim(xn("target_host"));
  100. $this->target_sock = trim(xn("target_sock"));
  101. $this->target_port = xi("target_port");
  102. $this->target_auth = xi("target_auth");
  103. $this->target_username = trim(xn("target_username"));
  104. $this->target_password = trim(xn("target_password"));
  105. $checkeds = xn("checked");
  106. if (is_array($checkeds)) {
  107. $this->selectedCollections = array_keys($checkeds);
  108. }
  109. if (empty($checkeds)) {
  110. $this->error = "Please select collections which you want to transfer.";
  111. $this->display();
  112. return;
  113. }
  114. if (empty($this->target_host) && empty($this->target_sock)) {
  115. $this->error = "Target host must not be empty.";
  116. $this->display();
  117. return;
  118. }
  119. $copyIndexes = xi("copy_indexes");
  120. /**if ($target === "") {
  121. $this->error = "Please enter a valid database name.";
  122. $this->display();
  123. return;
  124. }**/
  125. //start to transfer
  126. $targetOptions = array();
  127. if ($this->target_auth) {
  128. $targetOptions["username"] = $this->target_username;
  129. $targetOptions["password"] = $this->target_password;
  130. }
  131. $uri = null;
  132. if ($this->target_sock) {
  133. $uri = "mongodb://" . $this->target_sock;
  134. }
  135. else {
  136. $uri = "mongodb://" . $this->target_host . ":" . $this->target_port;
  137. }
  138. $targetConnection = new RMongo($uri, $targetOptions);
  139. $targetDb = $targetConnection->selectDB($this->db);
  140. if ($this->target_auth) {
  141. // "authenticate" can only be used between 1.0.1 - 1.2.11
  142. if (RMongo::compareVersion("1.0.1") >= 0 && RMongo::compareVersion("1.2.11") < 0) {
  143. $targetDb->authenticate($this->target_username, $this->target_password);
  144. }
  145. }
  146. $errors = array();
  147. foreach ($this->selectedCollections as $collectionName) {
  148. $ret = $targetDb->command(array(
  149. "cloneCollection" => $this->db . "." . $collectionName,
  150. "from" => $this->_server->uri(),
  151. "copyIndexes" => (bool)$copyIndexes
  152. ));
  153. if (!$ret["ok"]) {
  154. $errors[] = MMongo::readException($ret);
  155. break;
  156. }
  157. }
  158. if (!empty($errors)) {
  159. $this->error = implode("<br/>", $errors);
  160. $this->display();
  161. return;
  162. }
  163. $this->message = "All data were transfered to '{$this->target_host}' successfully.";
  164. }
  165. $this->display();
  166. }
  167. /** export db **/
  168. public function doDbExport() {
  169. $this->db = xn("db");
  170. $db = $this->_mongo->selectDB($this->db);
  171. $this->collections = MDb::listCollections($db);
  172. $this->selectedCollections = array();
  173. if (!$this->isPost()) {
  174. $this->selectedCollections[] = xn("collection");
  175. }
  176. else {
  177. $checkeds = xn("checked");
  178. $canDownload = xn("can_download");
  179. if (is_array($checkeds)) {
  180. $this->selectedCollections = array_keys($checkeds);
  181. }
  182. sort($this->selectedCollections);
  183. import("classes.VarExportor");
  184. $this->contents = "";
  185. $this->countRows = 0;
  186. //indexes
  187. foreach ($this->selectedCollections as $collection) {
  188. $collObj = $db->selectCollection($collection);
  189. $infos = $collObj->getIndexInfo();
  190. foreach ($infos as $info) {
  191. $options = array();
  192. if (isset($info["unique"])) {
  193. $options["unique"] = $info["unique"];
  194. }
  195. $exportor = new VarExportor($db, $info["key"]);
  196. $exportor2 = new VarExportor($db, $options);
  197. $this->contents .= "\n/** {$collection} indexes **/\ndb.getCollection(\"" . addslashes($collection) . "\").ensureIndex(" . $exportor->export(MONGO_EXPORT_JSON) . "," . $exportor2->export(MONGO_EXPORT_JSON) . ");\n";
  198. }
  199. }
  200. //data
  201. foreach ($this->selectedCollections as $collection) {
  202. $cursor = $db->selectCollection($collection)->find();
  203. $this->contents .= "\n/** " . $collection . " records **/\n";
  204. foreach ($cursor as $one) {
  205. $this->countRows ++;
  206. $exportor = new VarExportor($db, $one);
  207. $this->contents .= "db.getCollection(\"" . addslashes($collection) . "\").insert(" . $exportor->export(MONGO_EXPORT_JSON) . ");\n";
  208. unset($exportor);
  209. }
  210. unset($cursor);
  211. }
  212. if (x("can_download")) {
  213. $prefix = "mongo-" . urlencode($this->db) . "-" . date("Ymd-His");
  214. //gzip
  215. if (x("gzip")) {
  216. ob_end_clean();
  217. header("Content-type: application/x-gzip");
  218. header("Content-Disposition: attachment; filename=\"{$prefix}.gz\"");
  219. echo gzcompress($this->contents, 9);
  220. exit();
  221. }
  222. else {
  223. ob_end_clean();
  224. header("Content-type: application/octet-stream");
  225. header("Content-Disposition: attachment; filename=\"{$prefix}.js\"");
  226. echo $this->contents;
  227. exit();
  228. }
  229. }
  230. }
  231. $this->display();
  232. }
  233. /** import db **/
  234. public function doDbImport() {
  235. $this->db = xn("db");
  236. if ($this->isPost()) {
  237. $format = x("format");
  238. if (!empty($_FILES["json"]["tmp_name"])) {
  239. $tmp = $_FILES["json"]["tmp_name"];
  240. //read file by it's format
  241. $body = "";
  242. if (preg_match("/\\.gz$/", $_FILES["json"]["name"])) {
  243. $body = gzuncompress(file_get_contents($tmp));
  244. }
  245. else {
  246. $body = file_get_contents($tmp);
  247. }
  248. //check format
  249. $ret = array("ok" => 0);
  250. if ($format == "js") {
  251. $ret = $this->_mongo->selectDB($this->db)->execute('function (){ ' . $body . ' }');
  252. if (!$ret["ok"]) {
  253. $this->error = $ret["errmsg"];
  254. }
  255. else {
  256. $this->message = "All data import successfully.";
  257. }
  258. }
  259. else {
  260. $collection = trim(xn("collection"));
  261. if ($collection === "") {
  262. $this->error2 = "Please enter the collection name";
  263. }
  264. else {
  265. $lines = explode("\n", $body);
  266. foreach ($lines as $line) {
  267. $line = trim($line);
  268. if ($line) {
  269. $ret = $this->_mongo->selectDB($this->db)->execute('function (c, o){ o=eval("(" + o + ")"); db.getCollection(c).insert(o); }', array( $collection, $line ));
  270. }
  271. }
  272. if (!$ret["ok"]) {
  273. $this->error2 = $ret["errmsg"];
  274. }
  275. else {
  276. $this->message2 = "All data import successfully.";
  277. }
  278. }
  279. }
  280. }
  281. else {
  282. if ($format == "js") {
  283. $this->error = "Either no file input or file is too large to upload.";
  284. }
  285. else {
  286. $this->error2 = "Either no file input or file is too large to upload.";
  287. }
  288. }
  289. }
  290. $this->display();
  291. }
  292. /** db profiling **/
  293. public function doProfile() {
  294. $this->db = xn("db");
  295. import("lib.mongo.RQuery");
  296. import("lib.page.RPageStyle1");
  297. $query = new RQuery($this->_mongo, $this->db, "system.profile");
  298. $page = new RPageStyle1();
  299. $page->setTotal($query->count());
  300. $page->setSize(10);
  301. $page->setAutoQuery();
  302. $this->page = $page;
  303. $this->rows = $query
  304. ->offset($page->offset())
  305. ->limit($page->size())
  306. ->desc("ts")
  307. ->findAll();
  308. foreach ($this->rows as $index => $row) {
  309. $this->rows[$index]["text"] = $this->_highlight($row, "json");
  310. }
  311. $this->display();
  312. }
  313. /** change db profiling level **/
  314. public function doProfileLevel() {
  315. $this->db = xn("db");
  316. $db = $this->_mongo->selectDB($this->db);
  317. $query1 = $db->execute("function (){ return db.getProfilingLevel(); }");
  318. $this->level = $query1["retval"];
  319. if (x("go") == "save_level") {
  320. $level = xi("level");
  321. $slowms = xi("slowms");
  322. $db->execute("function(level,slowms) { db.setProfilingLevel(level,slowms); }", array($level, $slowms));
  323. $this->level = $level;
  324. }
  325. else {
  326. x("slowms", 50);
  327. }
  328. $this->display();
  329. }
  330. /** clear profiling data **/
  331. public function doClearProfile() {
  332. $this->db = xn("db");
  333. $db = $this->_mongo->selectDB($this->db);
  334. $query1 = $db->execute("function (){ return db.getProfilingLevel(); }");
  335. $oldLevel = $query1["retval"];
  336. $db->execute("function(level) { db.setProfilingLevel(level); }", array(0));
  337. $ret = $db->selectCollection("system.profile")->drop();
  338. $db->execute("function(level) { db.setProfilingLevel(level); }", array($oldLevel));
  339. $this->redirect("db.profile", array(
  340. "db" => $this->db
  341. ));
  342. }
  343. /** authentication **/
  344. public function doAuth() {
  345. $this->db = xn("db");
  346. $db = $this->_mongo->selectDB($this->db);
  347. //users
  348. $collection = $db->selectCollection("system.users");
  349. $cursor = $collection->find();
  350. $this->users= array();
  351. while($cursor->hasNext()) {
  352. $this->users[] = $cursor->getNext();
  353. }
  354. $this->display();
  355. }
  356. /** delete user **/
  357. public function doDeleteUser() {
  358. $this->db = xn("db");
  359. $db = $this->_mongo->selectDB($this->db);
  360. $db->execute("function (username){ db.removeUser(username); }", array(xn("user")));
  361. $this->redirect("db.auth", array(
  362. "db" => $this->db
  363. ));
  364. }
  365. /** add user **/
  366. public function doAddUser() {
  367. $this->db = xn("db");
  368. if (!$this->isPost()) {
  369. $this->display();
  370. return;
  371. }
  372. $username = trim(xn("username"));
  373. $password = trim(xn("password"));
  374. $password2 = trim(xn("password2"));
  375. if ($username == "") {
  376. $this->error = "You must supply a username for user.";
  377. $this->display();
  378. return;
  379. }
  380. if ($password == "") {
  381. $this->error = "You must supply a password for user.";
  382. $this->display();
  383. return;
  384. }
  385. if ($password != $password2) {
  386. $this->error = "Passwords you typed twice is not same.";
  387. $this->display();
  388. return;
  389. }
  390. $db = $this->_mongo->selectDB($this->db);
  391. $db->execute("function (username, pass, readonly){ db.addUser(username, pass, readonly); }", array(
  392. $username,
  393. $password,
  394. x("readonly") ? true : false
  395. ));
  396. $this->redirect("auth", array(
  397. "db" => $this->db
  398. ));
  399. }
  400. /** create new collection **/
  401. public function doNewCollection() {
  402. $this->db = xn("db");
  403. $this->name = trim(xn("name"));
  404. $this->isCapped = xi("is_capped");
  405. $this->size = xi("size");
  406. $this->max = xi("max");
  407. if ($this->isPost()) {
  408. $db = $this->_mongo->selectDB($this->db);
  409. MCollection::createCollection($db, $this->name, array(
  410. "capped" => $this->isCapped,
  411. "size" => $this->size,
  412. "max" => $this->max
  413. ));
  414. $this->message = "New collection is created. <a href=\"?action=collection.index&db={$this->db}&collection={$this->name}\">[GO &raquo;]</a>";
  415. //add index
  416. if (!$this->isCapped) {
  417. $db->selectCollection($this->name)->ensureIndex(array( "_id" => 1 ));
  418. }
  419. }
  420. $this->display();
  421. }
  422. /** drop all collections in a db **/
  423. public function doDropDbCollections() {
  424. $this->db = xn("db");
  425. $db = $this->_mongo->selectDB($this->db);
  426. foreach ($db->listCollections() as $collection) {
  427. $collection->drop();
  428. }
  429. echo '<script language="javascript">
  430. window.parent.frames["left"].location.reload();
  431. </script>';
  432. $this->redirect("db.index", array( "db" => $this->db ), true);
  433. }
  434. /** clear all records in all collections **/
  435. public function doClearDbCollections() {
  436. $this->db = xn("db");
  437. $db = $this->_mongo->selectDB($this->db);
  438. foreach ($db->listCollections() as $collection) {
  439. $collection->remove();
  440. }
  441. echo '<script language="javascript">
  442. window.parent.frames["left"].location.reload();
  443. </script>';
  444. $this->redirect("db.index", array( "db" => $this->db ), true);
  445. }
  446. /** repair dataase **/
  447. public function doRepairDatabase() {
  448. $this->db = xn("db");
  449. $db = $this->_mongo->selectDB($this->db);
  450. $ret = $db->command(array( "repairDatabase" => 1 ));
  451. //$ret = $db->execute('function (){ return db.repairDatabase(); }'); //occure error in current version, we did not know why?
  452. $this->ret = $this->_highlight($ret, "json");
  453. $this->display();
  454. }
  455. /** drop database **/
  456. public function doDropDatabase() {
  457. $this->db = xn("db");
  458. if (!x("confirm")) {
  459. $this->display();
  460. return;
  461. }
  462. $ret = $this->_mongo->dropDB($this->db);
  463. $this->ret = $this->_highlight($ret, "json");
  464. $this->display("dropDatabaseResult");
  465. }
  466. }
  467. ?>