forked from GNUsocial/gnu-social
		
	
		
			
				
	
	
		
			350 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * StatusNet - the distributed open-source microblogging tool
 | 
						|
 * Copyright (C) 2011, StatusNet, Inc.
 | 
						|
 *
 | 
						|
 * Installer class for domain-based multi-homing systems
 | 
						|
 *
 | 
						|
 * PHP version 5
 | 
						|
 *
 | 
						|
 * This program is free software: you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU Affero General Public License as published by
 | 
						|
 * the Free Software Foundation, either version 3 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU Affero General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Affero General Public License
 | 
						|
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 *
 | 
						|
 * @category  DomainStatusNetwork
 | 
						|
 * @package   StatusNet
 | 
						|
 * @author    Evan Prodromou <evan@status.net>
 | 
						|
 * @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 <evan@status.net>
 | 
						|
 * @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['DBHOST'];
 | 
						|
        $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('/<a[^>+]\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;
 | 
						|
    }
 | 
						|
}
 |