. * * @category DomainStatusNetwork * @package StatusNet * @author Evan Prodromou * @copyright 2011 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ if (!defined('STATUSNET')) { // This check helps protect against security problems; // your code file can't be executed directly from the web. exit(1); } /** * Installer class for domain-based multi-homing systems * * @category DomainStatusNetwork * @package StatusNet * @author Evan Prodromou * @copyright 2011 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ class DomainStatusNetworkInstaller extends Installer { protected $domain = null; protected $rootname = null; protected $sitedb = null; protected $rootpass = null; protected $nickname = null; protected $sn = null; public $verbose = false; function __construct($domain) { $this->domain = $domain; } /** * Go for it! * @return boolean success */ function main() { // We don't check prereqs. Check 'em before setting up a // multi-home system, kthxbi if ($this->prepare()) { return $this->handle(); } else { $this->showHelp(); return false; } } /** * Get our input parameters... * @return boolean success */ function prepare() { $config = $this->getConfig(); $this->nickname = DomainStatusNetworkPlugin::nicknameForDomain($this->domain); // XXX make this configurable $this->sitename = sprintf('The %s Status Network', $this->domain); $this->server = $this->nickname.'.'.$config['WILDCARD']; $this->path = null; $this->fancy = true; $datanick = $this->databaseize($this->nickname); $this->host = $config['DBHOSTNAME']; $this->database = $datanick.$config['DBBASE']; $this->dbtype = 'mysql'; // XXX: support others... someday $this->username = $datanick.$config['USERBASE']; // Max size for MySQL if (strlen($this->username) > 16) { $this->username = sprintf('%s%08x', substr($this->username, 0, 8), crc32($this->username)); } $pwgen = $config['PWDGEN']; $password = `$pwgen`; $this->password = trim($password); // For setting up the database $this->rootname = $config['ADMIN']; $this->rootpass = $config['ADMINPASS']; $this->sitehost = $config['SITEDBHOSTNAME']; $this->sitedb = $config['SITEDB']; $tagstr = $config['TAGS']; if (!empty($tagstr)) { $this->tags = preg_split('/[\s,]+/', $tagstr); } else { $this->tags = array(); } // Explicitly empty $this->adminNick = null; $this->adminPass = null; $this->adminEmail = null; $this->adminUpdates = null; /** Should we skip writing the configuration file? */ $this->skipConfig = true; if (!$this->validateDb()) { return false; } return true; } function handle() { return $this->doInstall(); } function setupDatabase() { $this->updateStatus('Creating database...'); $this->createDatabase(); parent::setupDatabase(); $this->updateStatus('Creating file directories...'); $this->createDirectories(); $this->updateStatus('Saving status network...'); $this->saveStatusNetwork(); $this->updateStatus('Checking schema for plugins...'); $this->checkSchema(); } function saveStatusNetwork() { Status_network::setupDB($this->sitehost, $this->rootname, $this->rootpass, $this->sitedb, array()); $sn = new Status_network(); $sn->nickname = $this->nickname; $sn->dbhost = $this->host; $sn->dbuser = $this->username; $sn->dbpass = $this->password; $sn->dbname = $this->database; $sn->sitename = $this->sitename; $result = $sn->insert(); if (!$result) { throw new ServerException("Could not create status_network: " . print_r($sn, true)); } // Re-fetch; stupid auto-increment integer isn't working $sn = Status_network::staticGet('nickname', $sn->nickname); if (empty($sn)) { throw new ServerException("Created {$this->nickname} status_network and could not find it again."); } // Set default tags $tags = $this->tags; // Add domain tag $tags[] = 'domain='.$this->domain; $sn->setTags($tags); $this->sn = $sn; } function checkSchema() { $config = $this->getConfig(); Status_network::$wildcard = $config['WILDCARD']; StatusNet::switchSite($this->nickname); // We need to initialize the schema_version stuff to make later setup easier $schema = array(); require INSTALLDIR.'/db/core.php'; $tableDefs = $schema; $schema = Schema::get(); $schemaUpdater = new SchemaUpdater($schema); foreach ($tableDefs as $table => $def) { $schemaUpdater->register($table, $def); } $schemaUpdater->checkSchema(); Event::handle('CheckSchema'); } function getStatusNetwork() { return $this->sn; } function createDirectories() { $config = $this->getConfig(); foreach (array('AVATARBASE', 'BACKGROUNDBASE', 'FILEBASE') as $key) { $base = $config[$key]; $dirname = $base.'/'.$this->nickname; // Make sure our bits are set $mask = umask(0); mkdir($dirname, 0770, true); umask($mask); // If you set the setuid bit on your base dirs this should be // unnecessary, but just in case. You must be root for this // to work. if (array_key_exists('WEBUSER', $config)) { chown($dirname, $config['WEBUSER']); } if (array_key_exists('WEBGROUP', $config)) { chgrp($dirname, $config['WEBGROUP']); } } } function createDatabase() { // Create the New DB $res = mysql_connect($this->host, $this->rootname, $this->rootpass); if (!$res) { throw new ServerException("Cannot connect to {$this->host} as {$this->rootname}."); } mysql_query("CREATE DATABASE ". mysql_real_escape_string($this->database), $res); $return = mysql_select_db($this->database, $res); if (!$return) { throw new ServerException("Unable to connect to {$this->database} on {$this->host}."); } foreach (array('localhost', '%') as $src) { mysql_query("GRANT ALL ON " . mysql_real_escape_string($this->database).".* TO '" . $this->username . "'@'".$src."' ". "IDENTIFIED BY '".$this->password."'", $res); } mysql_close($res); } function getConfig() { static $config; $cfg_file = "/etc/statusnet/setup.cfg"; if (empty($config)) { $result = parse_ini_file($cfg_file); $config = array(); foreach ($result as $key => $value) { $key = str_replace('export ', '', $key); $config[$key] = $value; } } return $config; } function showHelp() { } function warning($message, $submessage='') { print $this->html2text($message) . "\n"; if ($submessage != '') { print " " . $this->html2text($submessage) . "\n"; } print "\n"; } function updateStatus($status, $error=false) { if ($this->verbose || $error) { if ($error) { print "ERROR: "; } print $this->html2text($status); print "\n"; } } private function html2text($html) { // break out any links for text legibility $breakout = preg_replace('/+]\bhref="(.*)"[^>]*>(.*)<\/a>/', '\2 <\1>', $html); return html_entity_decode(strip_tags($breakout), ENT_QUOTES, 'UTF-8'); } function databaseize($nickname) { $nickname = str_replace('-', '_', $nickname); return $nickname; } }