Example #1
0
<?php

$login_required = FALSE;
require_once "../includes/page.php";
require_once "Subversion/StandaloneClient.php";
require_once "Subversion/PAStateStore.php";
require_once "{$path_prefix}/ext/JSON.php";
while (@ob_end_clean()) {
}
$state = new Subversion_PAStateStore($path_prefix);
?>
<h1>PeopleAggregator version information</h1>

<p><a href="system_update.php">system update</a> | version info</p>

<?php 
include dirname(__FILE__) . "/admin_login.php";
// --- past this point, we can assume the user is logged in as an admin ---
?>
<h2>Master version</h2>
<?php 
echo "<p>This is PeopleAggregator v<b>" . PA_VERSION . "</b>.</p>";
?>
<h2>Detailed version information</h2>
<?php 
if (file_exists("../../db/release_info.txt")) {
    ?>

<h3>Release info</h3>

<?php 
function main() {
    global $path_prefix;

    ?>

<h1>PeopleAggregator system update</h1>

<p>system update | <a href="version.php">version info</a></p>

    <?
        
    $tmp_dir = "$path_prefix/web/files";
    $tmp_fn = "$tmp_dir/update.treediff.xml";

    $state = new Subversion_PAStateStore($path_prefix);

    if (!$state->is_initialized()) $state->initialize();
    $client = new Subversion_StandaloneClient($state, $tmp_fn);
    
    $op = @$_POST['op'];
    switch ($op) {
    case 'login':
	break;
	
    case 'download':
	echo "<h2>downloading update</h2>";

        $root = $state->get_repository_root();

        if (preg_match("|^https://|", $root)) {
            echo "<p>ERROR: attempting to update from an HTTPS update server (<code>$root</code>), but we can't do HTTPS :-(</p>";
            break;
        }

        if (!preg_match("|^http://update.peopleaggregator.org/svn|", $root)) {
            echo '<p>WARNING: the update server is <code>'.$root.'</code>, which is not the official PeopleAggregator update server.</p>';
        }
        elseif ($root != 'http://update.peopleaggregator.org/svn/release') {
            echo '<p>WARNING: updating from '.$root.', which is on the official PeopleAggregator server, but may be a test release.</p>';
        }

	$rev = $state->get_revision();
	echo '<p>Requesting an update from revision r'.$rev.' from the server (<a href="'.$root.'">root</a>, <a href="'.$root.$state->get_repository_path().'">path</a>).</p>';
	
	$disp = new js_display();
	$disp->start();
	$client->displayer = $disp;
	$client->checkout();

        $err = NULL;
	$f = @fopen($tmp_fn, "rt");
	if ($f) {
            $xml = fread($f, 8192);
            fclose($f);
            if (!preg_match("|^<"."\?xml|", $xml)) {
                $err = "Invalid response received.";
            }
            else if (preg_match("|<m:human-readable.*?>(.*?)</m:human-readable>|s", $xml, $m)) {
                $err = $m[1];
            }
            else if (preg_match('|target-revision rev="(\d+)"|s', $xml, $m)) {
                $target_rev = (int)$m[1];
                if ($target_rev == $rev) {
                    echo "Your system is already up to date.";
                    unlink($tmp_fn);
                }
            }
	} else {
            $err = "Error reading temporary tree diff file $tmp_fn";
        }

        if ($err) {
            echo '<div class="error">An error occurred: <b>'.htmlspecialchars($err).'</b></div>';
            return;
        }

/*<?xml version="1.0" encoding="utf-8"?>
<D:error xmlns:D="DAV:" xmlns:m="http://apache.org/dav/xmlns" xmlns:C="svn:">
<C:error/>
<m:human-readable errcode="160005">
Cannot replace a directory from within
</m:human-readable>
</D:error>*/

	break;
	
    case 'test-apply':
        if (!file_exists($tmp_fn)) break;
    
	echo '<div id="progress-detail"><h2>Verifying that the update can be installed.</h2>'; flush();

	$msg_headers = array(
            "localmod" => "Your local modifications conflict with the update",
            "perms" => "The updater is unable to access some files or directories",
            );

	$client->displayer = new html_display();
	$msg_html = "";
	try {
	    $r = $client->apply_patch(FALSE);
	    $errors = $r['errors'];
            foreach ($errors as $level => $msgs) {
                $msg_list = "";
                foreach ($msgs as $msg) {
                    $msg_list .= "<li>".$msg."</li>";
                }
                $msg_html .= "<h3>".$msg_headers[$level]."</h3>
<ul>$msg_list</ul>";
            }
	} catch (Subversion_Failure $e) {
	    $msg_html = $e->getMessage();
	}

	echo <<<EOF
</div><!-- progress-detail -->
<script language="javascript" type="text/javascript"><!--
  // hide detail, so the user can see the error message
  document.getElementById("progress-detail").style.display = "none";
// --></script>
EOF;

	if ($msg_html) {
	    ?>

<p>The update (from r<?= $state->get_revision() ?> to r<?= $client->target_revision ?>) cannot be installed cleanly for the following reason(s):</p>

<div class="error"><?= $msg_html ?></div>

<p>You have several options at this point if you wish to install the update:</p>

<ol>

 <li>
  <p>Fix the issues listed above, then try installing the update again.</p>
  <? if (!@$errors['localmod']) { ?><p>HIGHLY RECOMMENDED - as the only issues above are to do with file access permissions.  Please fix the permissions, and try again.</p><? } ?>
  <? show_op("test-apply", "Click here to try installing the update again"); ?>
 </li>

 <? if (@$errors['localmod']) { ?>
 <li>
  <p>[NOT IMPLEMENTED YET] Migrate to using Subversion for updates.</p>
  <p>HIGHLY RECOMMENDED if you plan to maintain local changes.</p>
  <? show_op("svn-migrate", "Click here to create .svn folders in your PeopleAggregator install so you can use 'svn update'", TRUE); ?>
 </li>
 <? } ?>

 <li>
  <p>Overwrite your local changes.  This will probably result in a working system, but will destroy any changes you have made to your system, so make sure you know what you are doing!</p>
  <p>(Files with local modifications will be renamed, e.g. changedfile.php will become changedfile.php.local)</p>
  <? if (!@$errors['localmod']) { ?><p>NOT RECOMMENDED - as the only issues above are to do with file access permissions.  Instead, please fix the permissions, and try again.</p><? } ?>
  <? if (@$errors['perms']) { ?><p style="font-weight: bold">CURRENTLY NOT POSSIBLE due to the access permissions errors mentioned above.  Please fix them, then try again.</p><? } ?>
  <? show_op("force-apply", "Click here to install the update, overwriting your local changes.", @$errors['perms'] ? TRUE : FALSE); ?>
 </li>

 <li>
  <p>Install only the parts of the update that do not conflict with anything on your system.</p>
  <p>(Files with local modifications will not be touched, and new local files will block installation of new files or directories of the same name).</p>
  <p>This won't destroy anything you have changed, but could quite possibly result in a broken installation, so it is not recommended unless your changes are relatively minor.</p>
  <? if (!@$errors['localmod']) { ?><p>NOT RECOMMENDED - as the only issues above are to do with file access permissions.  Instead, please fix the permissions, and try again.</p><? } ?>
  <? show_op("soft-apply", "Click here to install the update without overwriting/deleting anything with local changes."); ?>
 </li>

</ol>

            <?
        } else {
	    show_op("apply", "Confirm - apply update to your installation");
	}
	return; // don't show 'an update has been downloaded' text

    case 'apply':
        if (!file_exists($tmp_fn)) break;
	echo "<h2>Applying update.</h2>";
	$client->displayer = new html_display();
	$client->apply_patch(TRUE);
        run_scripts();
	return;

    case 'soft-apply':
        if (!file_exists($tmp_fn)) break;
	echo "<h2>Applying update without overwriting local changes.</h2>";
	$client->displayer = new html_display();
	$client->apply_patch("soft");
        run_scripts();
	return;

    case 'force-apply':
        if (!file_exists($tmp_fn)) break;
	echo "<h2>Apply update, overwriting local changes.</h2>";
        echo "<p>Downloading extra files from the server ...</p><ul>";
        // find files to download
        $client->displayer = new null_display();
        $client->apply_patch();
	$client->displayer = new html_display();
        $client->download_incomplete_files($tmp_dir);
        echo "</ul>";

        // all done - now apply the patch
	$client->apply_patch("force");
        run_scripts();
	return;
	
    default:
	if ($op) throw new Subversion_Failure("Invalid operation: $op");
	break;
    }
    
    if (file_exists($tmp_fn)) {
	show_op("test-apply", "An update has been downloaded.  Click here to apply it to your system.");
    }
    else {
	show_op("download", "Check for updates");
    }
}
Example #3
0
function install_peopleaggregator()
{
    global $path_prefix;
    ?>

<h2>Detecting URLs</h2>

<ul>
<?php 
    // find base url (minus http:// suffix)
    if (!preg_match("|^(.*?)/config/index.php\$|", $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'], $m)) {
        dienow("Unable to find base URL");
    }
    $base_url_bare = $m[1];
    // make sure the base url is valid
    if (!can_get_peepagg_txt("http://{$base_url_bare}/peopleaggregator.txt")) {
        dienow("Unable to guess base URL - I think it should be http://{$base_url_bare}/ but that URL does not seem to work.");
    }
    note("Good: we can access the system at http://{$base_url_bare}/");
    // try stripping off the first url part (i.e. www.asdf -> asdf)
    $base_url_suffix = preg_replace("|^[^\\.]+\\.(.*)\$|", "\$1", $base_url_bare);
    $allow_spawning = FALSE;
    // check if it doesn't have any dots (e.g. http://colinux/web/config/)
    // - i.e. not suitable for sharing cookies over domains.
    if ($base_url_suffix == $base_url_bare) {
        note("Apparently running on an internal web server - not possible to run multiple networks.");
    } else {
        if (preg_match("|^\\d+\\.\\d+\\.\\d+\\.\\d+|", $base_url_bare)) {
            note("Running with an IP address rather than a domain name - not possible to run multiple networks.");
        } else {
            if (can_get_peepagg_txt("http://{$base_url_suffix}/peopleaggregator.txt")) {
                note("It looks like it is also accessible at <code>http://{$base_url_suffix}/</code>; trying <code>{$base_url_suffix}</code> as the root URL.");
            } else {
                note("It is not accessible at <code>http://{$base_url_suffix}/</code>; trying <code>{$base_url_bare}</code> as the root URL.");
                $base_url_suffix = $base_url_bare;
            }
            if (can_get_peepagg_txt("http://some-random-domain.{$base_url_suffix}/peopleaggregator.txt")) {
                note("It looks like the server is set up to host <code>*.{$base_url_suffix}</code>, so network spawning is possible.");
                $allow_spawning = TRUE;
            } else {
                warn("Wildcard domains do not appear to be enabled (cannot access the root of this install at http://some_random_domain.{$base_url_suffix}/) so network spawning will be disabled.");
            }
        }
    }
    global $base_url, $domain_suffix;
    if ($allow_spawning) {
        $base_url = "http://%network_name%.{$base_url_suffix}";
    } else {
        $base_url = "http://{$base_url_bare}";
    }
    $domain_suffix = preg_replace("|/.*\$|", "", $base_url_suffix);
    // stash $base_url away as config.inc will modify it
    $base_url_config = $base_url;
    note("Base URL: <code>{$base_url}</code>" . ($domain_suffix ? "; domain suffix: <code>{$domain_suffix}</code>" : ""));
    ?>
</ul>

<h2>Configuration</h2>

<?php 
    $admin_password = get_default("admin_password", "");
    $admin_password2 = get_default("admin_password2", "");
    $mysql_server = get_default("mysql_server", "localhost");
    $mysql_dbname = get_default("mysql_dbname", "peopleaggregator");
    $mysql_username = get_default("mysql_username", "peopleaggregator");
    $mysql_password = get_default("mysql_password", "");
    $mysql_root_username = get_default("mysql_root_username", "root");
    $mysql_root_password = get_default("mysql_root_password", "");
    $home_network_config = str_replace("%network_name%", "www", $base_url) . "/config/";
    ?>

<form method="POST" action="<?php 
    echo $home_network_config;
    ?>
#check">
<div class="config">

<p>Some operations (upgrading, and content administration) require an administrator password for access.  Please enter an administrator password here.</p>

<div class="config_item"><label for="admin_password">Admin password</label>
 <input type="password" id="admin_password" name="admin_password" value="<?php 
    echo $admin_password;
    ?>
"><?php 
    if (!$admin_password) {
        echo " &larr; must not be blank!";
    }
    ?>
</div>
<div class="config_item"><label for="admin_password">Repeat admin password</label>
 <input type="password" id="admin_password2" name="admin_password2" value="<?php 
    echo $admin_password2;
    ?>
"><?php 
    if (!$admin_password2) {
        echo " &larr; must not be blank!";
    } else {
        if ($admin_password != $admin_password2) {
            echo " &larr; must be the same as above!";
        }
    }
    ?>
</div>

<p>Enter your database details below.</p>

<div class="config_item"><label for="mysql_server">MySQL server</label>
 <input type="text" name="mysql_server" value="<?php 
    echo $mysql_server;
    ?>
"></div>
<div class="config_item"><label for="mysql_dbname">MySQL database name</label>
 <input type="text" name="mysql_dbname" value="<?php 
    echo $mysql_dbname;
    ?>
"></div>
<div class="config_item"><label for="mysql_username">MySQL username</label>
 <input type="text" name="mysql_username" value="<?php 
    echo $mysql_username;
    ?>
"></div>
<div class="config_item"><label for="mysql_password">MySQL password</label>
 <input type="password" name="mysql_password" value="<?php 
    echo $mysql_password;
    ?>
"><?php 
    if (!$mysql_password) {
        echo " &larr; must not be blank!";
    }
    ?>
</div>

<p>If the database has not been created yet, you can enter your database administrator ("root") login details here to have it created automatically:</p>

<div class="config_item"><label for="mysql_root_username">Administrator username</label>
 <input type="text" name="mysql_root_username" value="<?php 
    echo $mysql_root_username;
    ?>
"></div>
<div class="config_item"><label for="mysql_root_password">Administrator password</label>
 <input type="password" name="mysql_root_password" value="<?php 
    echo $mysql_root_password;
    ?>
"></div>

<p><input type="submit" value="Set up PeopleAggregator"></p>

</div>
</form>
<?php 
    // only exec the rest after someone clicks 'setup'
    if (!$_POST) {
        exit;
    }
    // wrap install process in exception handler so we can roll back
    $rollback_cmds = array();
    try {
        ?>
<h2 id="check">Checking config details</h2>

<ul>
<?php 
        if (!$admin_password) {
            focus_field("admin_password");
            dienow("You must supply an admin password");
        }
        if ($admin_password != $admin_password2) {
            focus_field("admin_password");
            dienow("Both admin paswords must be the same");
        }
        if (!$mysql_password) {
            focus_field("mysql_password");
            dienow("You may not use a blank password for the MySQL connection");
        }
        $user_link = @mysql_connect($mysql_server, $mysql_username, $mysql_password);
        if ($user_link) {
            note("Able to connect to the MySQL server at {$mysql_server} with supplied login details.");
            // make sure the DB isn't already populated
            if (!mysql_select_db($mysql_dbname, $user_link)) {
                note("Database does not exist or is inaccessible");
                mysql_close($user_link);
                $user_link = FALSE;
            } else {
                $sth = run_query("SHOW TABLES", $user_link);
                if (mysql_num_rows($sth)) {
                    throw new Installation_Failure("The database {$mysql_dbname} already contains data.  Please wipe it out or recreate the database before installing PeopleAggregator.  If PeopleAggregator is already installed here, you will have to create your local_config.php file manually.");
                }
            }
        } else {
            note("Unable to connect to the MySQL server using the supplied login details");
        }
        if (!$user_link) {
            note("Trying administrator login...");
            $admin_link = @mysql_connect($mysql_server, $mysql_root_username, $mysql_root_password);
            if (!$admin_link) {
                dienow("Unable to connect to the MySQL server with the supplied login details or as an administrator");
            }
            note("Able to connect to the MySQL server with the supplied administrator login details - a new database will be created.");
            // make sure the db doesn't already exist
            if (mysql_select_db($mysql_dbname, $admin_link)) {
                throw new Installation_Failure("Database {$mysql_dbname} already exists");
            }
            // create it
            $sql = "CREATE DATABASE " . db_esc($mysql_dbname);
            $rollback_cmds[] = array("sql", "DROP DATABASE " . db_esc($mysql_dbname), $admin_link);
            run_query($sql, $admin_link);
            // now grant permissions with successively looser hostnames until
            // we find one that lets the web server access the database.
            foreach (array("localhost", "localhost.localdomain", $_SERVER['SERVER_NAME'], gethostbyname($_SERVER['SERVER_NAME']), "%") as $server_host) {
                $sql = "GRANT ALL ON " . db_esc($mysql_dbname) . ".* TO " . db_esc($mysql_username) . "@" . db_esc($server_host) . " IDENTIFIED BY '" . mysql_real_escape_string($mysql_password) . "'";
                run_query($sql, $admin_link);
                if (($user_link = mysql_connect($mysql_server, $mysql_username, $mysql_password)) && mysql_select_db($mysql_dbname, $user_link)) {
                    note("Successfully logged in to new database using credentials from host {$server_host}");
                    break;
                }
            }
            if (!$user_link) {
                throw new Installation_Failure("Failed to grant access credentials that would allow the web server to access the database.  Please try creating the database manually.");
            }
        }
        if (!$user_link) {
            throw new Installation_Failure("Something went wrong - we should have successfully connected to the DB by now");
        }
        // set all local_config.php vars
        global $peepagg_dsn;
        $peepagg_dsn = "mysql://{$mysql_username}:{$mysql_password}@{$mysql_server}/{$mysql_dbname}";
        $logger_logFile = "{$path_prefix}/log/pa.log";
        $default_relation_id = 1;
        // now write out local_config.php
        $local_config_text = "<" . "?php\n\n// local_config.php: This file contains server-specific settings like\n// the database password, the base URL of this installation, and\n// debugging flags.  Anything in default_config.php can be overridden\n// here.\n\n// If you want to change project-specific things like the site name,\n// you can use project_config.php.\n\n// Global defaults, which are shared by all other PeopleAggregator\n// installations, are in default_config.php.\n\n// Database details.\n\$peepagg_dsn = \"{$peepagg_dsn}\";\n\n// URL to the root of the server.\n\$base_url = \"{$base_url_config}\";\n\n// Parent domain part of the URL.\n\$domain_suffix = \"{$domain_suffix}\";\n";
        if ($allow_spawning) {
            $local_config_text .= "\n// Network operation is enabled.  To disable, set \$_PA->enable_networks\n// to FALSE.  To disable network spawning without deactivating existing\n// networks, set \$_PA->enable_network_spawning to FALSE.\n";
        } else {
            $local_config_text .= "\n// Network operation disabled as wildcard domains are not configured.\n// Comment out the following line to enable network creation (after\n// configuring wildcard DNS, etc).\n\$_PA->enable_networks = FALSE;\n";
        }
        $local_config_text .= "\n// Path to log file (you may wish to change this to /var/log/somewhere/pa.log).\n\$logger_logFile = \"\$path_prefix/log/pa.log\";\n\n// Administration password\n\$admin_password = \"{$admin_password}\";\n\n// When a new user registers on the site, they will automatically be marked as a friend of the user with this ID.\n// (The default is 1, so everyone will be a friend of the first user.)\n\$default_relation_id = {$default_relation_id};\n\n?" . ">\n";
        global $config_fn;
        note("Writing local_config.php");
        $rollback_cmds[] = array("delete", $config_fn);
        if (!file_put_contents($config_fn, $local_config_text)) {
            throw new Installation_Failure("Unable to write {$config_fn}");
        }
        // define LOCAL_CONFIG_OVERRIDE to tell config.inc to load our new
        // temporary local_config.php rather than look for it in the global
        // location
        define("LOCAL_CONFIG_LOCATION_OVERRIDE", $config_fn);
        // now set up databases
        note("Initializing database ... ");
        run_query_file(dirname(__FILE__) . "/../../db/PeepAgg.mysql", $user_link);
        note("Running database upgrade script and installing default module settings ... ");
        try {
            require_once dirname(__FILE__) . "/../update/run_scripts.php";
            run_update_scripts();
        } catch (Exception $e) {
            throw new Installation_Failure("Error updating database or installing default module settings: " . $e->getMessage());
        }
        global $do_auto_update;
        if (!$do_auto_update) {
            note("Skipping auto-upgrade preparation as it is disabled for this installation.");
        } else {
            note("Preparing system for auto-upgradeability ... ");
            require_once "Subversion/PAStateStore.php";
            try {
                $store = new Subversion_PAStateStore($path_prefix);
                $store->initialize();
                note("Subversion update root: <code>" . $store->get_repository_root() . "</code>; path: <code>" . $store->get_repository_path() . "</code>; revision: " . $store->get_revision());
            } catch (Exception $e) {
                throw new Installation_Failure("Error preparing auto-upgrade system: " . $e->getMessage());
            }
        }
        ?>
</ul>

<h2>All done!</h2>

<p class="good">Your database has been initialized and a <code>local_config.php</code> file has been written at <code><?php 
        echo $config_fn;
        ?>
</code>.  To finish the installation, please move this file up into the parent of the 'web' directory, then <a href="../">click here</a>.</p>

<p>The following command will do this on Linux/UNIX:</p>

<p style="margin-left: 5em"><code>mv <?php 
        echo realpath($config_fn);
        ?>
 <?php 
        echo $path_prefix;
        ?>
/</code></p>

<?php 
        //throw new Installation_Failure("foo");
    } catch (Installation_Failure $e) {
        warn("Installation failed (" . $e->getMessage() . ") - undoing operations");
        foreach (array_reverse($rollback_cmds) as $cmd) {
            switch ($cmd[0]) {
                case 'sql':
                    list(, $sql, $link) = $cmd;
                    note("DB query: {$sql}");
                    mysql_query($sql, $link);
                    break;
                case 'delete':
                    list(, $fn) = $cmd;
                    note("Delete: {$fn}");
                    unlink($fn);
                    break;
                default:
                    warn("Unknown rollback command type: " . $cmd[0]);
                    break;
            }
        }
    }
}