Skip to content
This repository has been archived by the owner on Jul 5, 2023. It is now read-only.

Commit

Permalink
Clean up any lingering empty string server DSNs
Browse files Browse the repository at this point in the history
(PHP backend)

See #108
  • Loading branch information
bobthecow committed May 2, 2013
1 parent 97f7168 commit 240bf66
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 2 deletions.
2 changes: 1 addition & 1 deletion genghis.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Genghis_Models_Database implements ArrayAccess, Genghis_JsonEncodable { pu
class Genghis_Models_Server implements ArrayAccess, Genghis_JsonEncodable { public $dsn; public $name; public $options; public $default; public $db; public $error; private $connection; private $databases = array(); public function __construct($dsn, $default = false) { $this->default = $default; try { $config = self::parseDsn($dsn); $this->name = $config['name']; $this->dsn = $config['dsn']; $this->options = $config['options']; if (isset($config['db'])) { $this->db = $config['db']; } } catch (Genghis_HttpException $e) { $this->name = $dsn; $this->dsn = $dsn; $this->error = $e->getMessage(); } } public function offsetExists($name) { $list = $this->listDBs(); foreach ($list['databases'] as $db) { if ($db['name'] === $name) { return true; } } return false; } public function offsetGet($name) { if (!isset($this[$name])) { throw new Genghis_HttpException(404, sprintf("Database '%s' not found on '%s'", $name, $this->name)); } if (!isset($this->databases[$name])) { $this->databases[$name] = new Genghis_Models_Database($this, $name); } return $this->databases[$name]; } public function getConnection() { if (!isset($this->connection)) { $this->connection = new Mongo($this->dsn, array_merge(array('connectTimeoutMS' => 1000), $this->options)); } return $this->connection; } public function createDatabase($name) { if (isset($this[$name])) { throw new Genghis_HttpException(400, sprintf("Database '%s' already exists on '%s'", $name, $this->name)); } try { $db = $this->connection->selectDB($name); } catch (Exception $e) { if (strpos($e->getMessage(), 'invalid name') !== false) { throw new Genghis_HttpException(400, 'Invalid database name'); } throw $e; } $db->selectCollection('__genghis_tmp_collection__')->drop(); return $this[$name]; } public function listDatabases() { $dbs = array(); $list = $this->listDBs(); foreach ($list['databases'] as $db) { $dbs[] = $this[$db['name']]; } return $dbs; } public function getDatabaseNames() { $names = array(); $list = $this->listDBs(); foreach ($list['databases'] as $db) { $names[] = $db['name']; } return $names; } public function offsetSet($name, $value) { throw new Exception; } public function offsetUnset($name) { $this[$name]->drop(); } public function asJson() { $server = array( 'id' => $this->name, 'name' => $this->name, 'editable' => !$this->default, ); if (isset($this->error)) { $server['error'] = $this->error; return $server; } try { $res = $this->listDBs(); if (isset($res['errmsg'])) { $server['error'] = sprintf("Unable to connect to Mongo server at '%s': %s", $this->name, $res['errmsg']); return $server; } $dbs = $this->getDatabaseNames(); return array_merge($server, array( 'size' => $res['totalSize'], 'count' => count($dbs), 'databases' => $dbs, )); } catch (Exception $e) { $server['error'] = sprintf("Unable to connect to Mongo server at '%s'", $this->name); return $server; } } const DSN_PATTERN = "~^(?:mongodb://)?(?:(?P<username>[^:@]+):(?P<password>[^@]+)@)?(?P<host>[^,/@:]+)(?::(?P<port>\d+))?(?:/(?P<database>[^\?]+)?(?:\?(?P<options>.*))?)?$~"; public static function parseDsn($dsn) { $chunks = array(); if (!preg_match(self::DSN_PATTERN, $dsn, $chunks)) { throw new Genghis_HttpException(400, 'Malformed server DSN'); } if (strpos($dsn, 'mongodb://') !== 0) { $dsn = 'mongodb://'.$dsn; } $dsnOpts = array(); $options = array(); if (isset($chunks['options'])) { parse_str(str_replace(';', '&', $chunks['options']), $dsnOpts); foreach ($dsnOpts as $name => $value) { switch ($name) { case 'replicaSet': $options[$name] = (string) $value; break; case 'connectTimeoutMS': case 'socketTimeoutMS': $options[$name] = intval($value); break; case 'slaveOk': case 'safe': case 'w': case 'wtimeoutMS': case 'fsync': case 'journal': throw new Genghis_HttpException(400, 'Unsupported connection option - ' . $name); default: throw new Genghis_HttpException(400, 'Malformed server DSN: Unknown connection option - ' . $name); } } } $name = $chunks['host']; if (isset($chunks['username']) && !empty($chunks['username'])) { $name = $chunks['username'].'@'.$name; } if (isset($chunks['port']) && !empty($chunks['port'])) { $port = intval($chunks['port']); if ($port !== 27017) { $name .= ':'.$port; } } if (isset($chunks['database']) && !empty($chunks['database']) && $chunks['database'] != 'admin') { $db = $chunks['database']; $name .= '/'.$db; } $ret = compact('name', 'dsn', 'options'); if (isset($db)) { $ret['db'] = $db; } return $ret; } private function listDBs() { if (isset($this->db)) { $stats = $this->getConnection() ->selectDB($this->db) ->command(array('dbStats' => true)); return array( 'totalSize' => $stats['fileSize'], 'databases' => array(array('name' => $this->db)), ); } return $this->getConnection()->listDBs(); } }
class Genghis_RedirectResponse extends Genghis_Response { public function __construct($url, $status = 301) { parent::__construct($url, $status); } public function render() { header(sprintf('Location: %s', $this->data), $this->status); } }
class Genghis_Response { protected static $statusCodes = array( 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 204 => 'No Content', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 400 => 'Bad Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 412 => 'Precondition Failed', 415 => 'Unsupported Media Type', 417 => 'Expectation Failed', 500 => 'Internal Server Error', 501 => 'Not Implemented', ); protected $data = ''; protected $status = 200; protected $headers = array(); public function __construct($data, $status = 200, $headers = array()) { $this->data = $data; $this->status = $status; $this->headers = $headers; } public function render() { $this->renderHeaders(); $this->renderContent(); } public static function getStatusText($status) { if (isset(self::$statusCodes[$status])) { return self::$statusCodes[$status]; } } protected function renderHeaders() { header(sprintf('HTTP/1.0 %s %s', $this->status, self::$statusCodes[$this->status])); foreach ($this->headers as $name => $val) { header(sprintf('%s: %s', $name, $val)); } } protected function renderContent() { print((string) $this->data); } }
class Genghis_ServerCollection implements ArrayAccess, Genghis_JsonEncodable { private $serverDsns; private $servers; private $defaultServerDsns; private $defaultServers; public function __construct(array $servers = null, array $defaultServers = null) { $this->serverDsns = $servers; $this->defaultServerDsns = $defaultServers; } public function offsetExists($name) { $this->initDsns(); return isset($this->serverDsns[$name]) || isset($this->defaultServerDsns[$name]); } public function offsetGet($name) { $this->initServers(); if (!isset($this[$name])) { throw new Genghis_HttpException(404, sprintf("Server '%s' not found", $name)); } if (!isset($this->servers[$name])) { if (isset($this->serverDsns[$name])) { $this->servers[$name] = new Genghis_Models_Server($this->serverDsns[$name]); } elseif (isset($this->defaultServerDsns[$name])) { $this->servers[$name] = new Genghis_Models_Server($this->defaultServerDsns[$name], true); } } return $this->servers[$name]; } public function offsetSet($name, $server) { $this->initServers(); if (!$server instanceof Genghis_Models_Server) { throw new Exception('Invalid Server instance'); } if (isset($this->serverDsns[$server->name])) { throw new Genghis_HttpException(400, sprintf("Server '%s' already exists", $server->name)); } $this->serverDsns[$server->name] = $server->dsn; $this->servers[$server->name] = $server; $this->saveServers(); } public function offsetUnset($name) { $this->initServers(); if (!isset($this->servers[$name])) { throw new Genghis_HttpException(404, sprintf("Server '%s' not found", $name)); } unset($this->servers[$name]); $this->saveServers(); } public function asJson() { $this->initServers(); return array_values($this->servers); } private function initDsns() { if (!isset($this->serverDsns)) { $this->serverDsns = array(); if (isset($_COOKIE['genghis_servers']) && $localDsns = $this->decodeJson($_COOKIE['genghis_servers'])) { foreach ($localDsns as $dsn) { try { $info = Genghis_Models_Server::parseDsn($dsn); $this->serverDsns[$info['name']] = $info['dsn']; } catch (Genghis_HttpException $e) { $this->serverDsns[$dsn] = $dsn; } } } } if (!isset($this->defaultServerDsns)) { $this->defaultServerDsns = array(); $defaultDsns = array_merge( isset($_ENV['GENGHIS_SERVERS']) ? explode(';', $_ENV['GENGHIS_SERVERS']) : array(), isset($_SERVER['GENGHIS_SERVERS']) ? explode(';', $_SERVER['GENGHIS_SERVERS']) : array() ); foreach ($defaultDsns as $dsn) { try { $info = Genghis_Models_Server::parseDsn($dsn); $this->defaultServerDsns[$info['name']] = $info['dsn']; } catch (Genghis_HttpException $e) { $this->defaultServerDsns[$dsn] = $dsn; } } } if (empty($this->serverDsns) && empty($this->defaultServerDsns)) { $this[] = new Genghis_Models_Server('localhost:27017'); } } private function initServers() { if (!isset($this->servers)) { $this->servers = array(); $this->initDsns(); foreach (array_merge(array_keys($this->serverDsns), array_keys($this->defaultServerDsns)) as $name) { $this[$name]; } } } private function decodeJson($data) { $json = json_decode($data, true); if ($json === false && trim($data) != '') { throw new Genghis_HttpException(400, 'Malformed document'); } return $json; } private function saveServers() { $servers = array(); foreach ($this->servers as $server) { if (!$server->default) { $servers[] = $server->dsn; } } setcookie('genghis_servers', json_encode($servers), time()+60*60*24*365, '/'); } }
class Genghis_ServerCollection implements ArrayAccess, Genghis_JsonEncodable { private $serverDsns; private $servers; private $defaultServerDsns; private $defaultServers; public function __construct(array $servers = null, array $defaultServers = null) { $this->serverDsns = $servers; $this->defaultServerDsns = $defaultServers; } public function offsetExists($name) { $this->initDsns(); return isset($this->serverDsns[$name]) || isset($this->defaultServerDsns[$name]); } public function offsetGet($name) { $this->initServers(); if (!isset($this[$name])) { throw new Genghis_HttpException(404, sprintf("Server '%s' not found", $name)); } if (!isset($this->servers[$name])) { if (isset($this->serverDsns[$name])) { $this->servers[$name] = new Genghis_Models_Server($this->serverDsns[$name]); } elseif (isset($this->defaultServerDsns[$name])) { $this->servers[$name] = new Genghis_Models_Server($this->defaultServerDsns[$name], true); } } return $this->servers[$name]; } public function offsetSet($name, $server) { $this->initServers(); if (!$server instanceof Genghis_Models_Server) { throw new Exception('Invalid Server instance'); } if (isset($this->serverDsns[$server->name])) { throw new Genghis_HttpException(400, sprintf("Server '%s' already exists", $server->name)); } $this->serverDsns[$server->name] = $server->dsn; $this->servers[$server->name] = $server; $this->saveServers(); } public function offsetUnset($name) { $this->initServers(); if (!isset($this->servers[$name])) { throw new Genghis_HttpException(404, sprintf("Server '%s' not found", $name)); } unset($this->servers[$name]); $this->saveServers(); } public function asJson() { $this->initServers(); return array_values($this->servers); } private function initDsns() { if (!isset($this->serverDsns)) { $this->serverDsns = array(); if (isset($_COOKIE['genghis_servers']) && $localDsns = $this->decodeJson($_COOKIE['genghis_servers'])) { foreach ($localDsns as $dsn) { try { $info = Genghis_Models_Server::parseDsn($dsn); $this->serverDsns[$info['name']] = $info['dsn']; } catch (Genghis_HttpException $e) { $this->serverDsns[$dsn] = $dsn; } } } } if (!isset($this->defaultServerDsns)) { $this->defaultServerDsns = array(); $defaultDsns = array_merge( isset($_ENV['GENGHIS_SERVERS']) ? explode(';', $_ENV['GENGHIS_SERVERS']) : array(), isset($_SERVER['GENGHIS_SERVERS']) ? explode(';', $_SERVER['GENGHIS_SERVERS']) : array() ); foreach ($defaultDsns as $dsn) { try { $info = Genghis_Models_Server::parseDsn($dsn); $this->defaultServerDsns[$info['name']] = $info['dsn']; } catch (Genghis_HttpException $e) { $this->defaultServerDsns[$dsn] = $dsn; } } } if (empty($this->serverDsns) && empty($this->defaultServerDsns)) { $this[] = new Genghis_Models_Server('localhost:27017'); } } private function initServers() { if (!isset($this->servers)) { $this->servers = array(); $this->initDsns(); foreach (array_merge(array_keys($this->serverDsns), array_keys($this->defaultServerDsns)) as $name) { $this[$name]; } } } private function decodeJson($data) { $json = json_decode($data, true); if ($json === false && trim($data) != '') { throw new Genghis_HttpException(400, 'Malformed document'); } return $json; } private function saveServers() { $servers = array(); foreach ($this->servers as $server) { if (!$server->default && $server->name) { $servers[] = $server->dsn; } } setcookie('genghis_servers', json_encode($servers), time()+60*60*24*365, '/'); } }


$app = new Genghis_App(new Genghis_AssetLoader_Inline(__FILE__, __COMPILER_HALT_OFFSET__));
Expand Down
2 changes: 1 addition & 1 deletion src/php/Genghis/ServerCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private function saveServers()
{
$servers = array();
foreach ($this->servers as $server) {
if (!$server->default) {
if (!$server->default && $server->name) {
$servers[] = $server->dsn;
}
}
Expand Down

0 comments on commit 240bf66

Please sign in to comment.