_('Quick Install'),
'ico' => 'images/ocilogo.png',
'link' => 'toggle',
'pos' => 11,
'links' => array(),
);
// @TODO invoke a hook to get supported applications
// need: id (eg. wordpress), weight (to order), ico, and
// optionally - a different action path.
// @TODO required binaries for installation: eg, wp-cli, drush
if ($this->app_is_installable('wordpress')) {
$menu['links'][] = array(
'txt' => _('WordPress'),
'url' => 'oci_install.php?app=wordpress',
'ico' => 'images/wordpress.png',
);
}
if ($this->app_is_installable('drupal')) {
$menu['links'][] = array(
'txt' => _('Drupal'),
'url' => 'oci_install.php?app=drupal',
'ico' => 'images/drupal.png',
);
}
if ($menu['links']) {
return $menu;
}
}
/**
* Checks to see if requirements are met to install an application.
*
* @param $app string
* The string identifier of the application (eg. drupal, wordpress).
*/
function app_is_installable($app) {
global $hooks;
$vals = $hooks->invoke('hook_oci_is_installable', array($app));
foreach ($vals as $class => $rval) {
if ($rval) {
return TRUE;
}
}
return FALSE;
}
/**
* Implements hook_oci_is_installable().
*/
function hook_oci_is_installable($app) {
global $L_ALTERNC_DRUSH_BIN, $L_ALTERNC_WP_BIN;
switch ($app) {
case 'drupal':
if ($L_ALTERNC_DRUSH_BIN) {
return TRUE;
}
break;
case 'wordpress':
if ($L_ALTERNC_WP_BIN) {
return TRUE;
}
break;
}
return FALSE;
}
/**
* Gets which fields should be loaded for the one click install form.
*
* @param $app string
*
* @returns array
* Array of fields indexed by parameter name. Each value is an array
* of ["fetch_type", "data_type", "default"].
* fetch_type may be "get" or "post".
*/
function oci_form_fields($app) {
global $hooks;
$fields = array(
'application' => array('post', 'string', ''), // Used in confirmation.
'domain' => array('post', 'string', ''),
'new_domain_name' => array('post', 'string', ''),
'sub_domain' => array('post', 'string', ''),
'new_sub_domain_name' => array('post', 'string'),
'new_sub_domain_path' => array('post', 'string', ''),
'new_sub_domain_type' => array('post', 'string', 'vhost'),
'db_name' => array('post', 'string', ''),
'new_db_name' => array('post', 'string', ''),
'db_prefix' => array('post', 'string', ''),
);
$vals = $hooks->invoke('hook_oci_form_fields', array($app));
foreach ($vals as $v) {
$fields = $fields + $v;
}
return $fields;
}
/**
* Implements hook_oci_form_fields().
*/
function hook_oci_form_fields($app) {
global $mem;
if ($app == 'drupal') {
$fields = array(
'drupal_install_source' => array('post', 'string', ''),
'drupal_makefile' => array('post', 'string', ''),
'drupal_core_version' => array('post', 'string', ''),
'drupal_title' => array('post', 'string', ''),
'drupal_admin_name' => array('post', 'string', 'admin'),
// @TODO use user e-mail as a default
'drupal_admin_mail' => array('post', 'string', ''),
'drupal_site_name' => array('post', 'string', ''),
'drupal_site_mail' => array('post', 'string', ''),
);
return $fields;
}
if ($app == 'wordpress') {
$fields = array(
'wordpress_title' => array('post', 'string', ''),
'wordpress_admin_mail' => array('post', 'string', ''),
'wordpress_admin_name' => array('post', 'string', 'admin'),
'wordpress_locale' => array('post', 'string', ''),
);
return $fields;
}
return array();
}
/**
* Helper function to get the action script path.
*
* @returns string
* String containing the name of the php script which should be
* invoked to run the installation.
*/
function get_app_action($app) {
return 'oci_doinstall_' . $app . '.php';
}
/**
* Returns a list of subdomain types which can be used for
* installing applications into.
*
* @returns array
* Array of vhost types (strings).
*/
function allowed_subdomain_types() {
// Maybe just there the type has target DIRECTORY.
global $dom;
$dtypes = $dom->domains_type_lst();
$types = array();
foreach ($dtypes as $name => $record) {
if ($record['target'] == 'DIRECTORY') {
$types[] = $name;
}
}
return $types;
}
/**
* Provides the a base form for installation of applications.
*
* @param $app string
* The string identifier of the application (eg. drupal, wordpress).
*/
function oci_form($app) {
global $hooks, $quota, $dom, $mysql;
$form = "
";
return $form;
}
/**
* Implements hook_oci_form.
*/
function hook_oci_form($app) {
$f = '';
switch ($app) {
case 'drupal':
// These fields should be defined in hook_oci_form_fields
// Choose the install source
$f .= '
';
$f .= '';
$f .= '
';
// Core Version
$f .= '
';
$f .= '';
$f .= '
';
// Makefile
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// Site Title
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// Drupal Admin Name
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// Drupal Admin Mail
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// Drupal Site Mail
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// Drupal Site Name
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
break;
case 'wordpress':
// Site Title
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// wordpress Admin Name
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// wordpress Admin Mail
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
// wordpress locale
$f .= '
';
$f .= '';
$f .= '';
$f .= '
';
break;
default:
break;
}
return $f;
}
/**
* Perform validation of the form data.
*
* @param array $vars
* Array of name/value for the submitted data as received in oci_confirm.php
*
* @returns array
* Array of errors eg. array(0 => array('module' => 'm_oci', 'message' => '...'), ...)
*/
function oci_form_validate($app, $vars) {
global $hooks, $dom, $db;
$errors = array();
if ($vars['domain'] == '*new*') {
if (!$vars['new_domain_name']) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('new_domain_name must not be empty when trying to create new domain'),
);
}
// Repeat validation done in m_dom::add_domain
if (checkfqdn(strtolower($vars['new_domain_name']))) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('new_domain_name is syntaxically incorrect'),
);
}
$db->query("SELECT domain FROM forbidden_domains WHERE domain= ? ;", array($domain));
if ($db->num_rows()) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('new_domain_name is forbidden on this server'),
);
}
if ($domain == $L_FQDN || $domain == "www.$L_FQDN") {
$errors[] = array(
'module' => 'm_oci',
'message' => _('new_domain_name is the server\'s domain. You cannot host it on your account'),
);
}
$db->query("SELECT compte FROM domaines WHERE domaine= ?;", array($domain));
if ($db->num_rows()) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('The domain already exists'),
);
}
$db->query("SELECT compte FROM `sub_domaines` WHERE sub != \"\" AND concat( sub, \".\", domaine )= ? OR domaine= ?;", array($domain, $domain));
if ($db->num_rows()) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('The domain already exists'),
);
}
// There are so many more... whois, dns, quota
}
$sub = '';
if ($vars['sub_domain'] == '*new*') {
if (!$vars['new_sub_domain_name']) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('new_sub_domain_name must not be empty'),
);
}
if (!$vars['new_sub_domain_path']) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('new_sub_domain_path must not be empty'),
);
}
if (!$vars['new_sub_domain_type']) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('new_sub_domain_type must not be empty'),
);
}
} else {
// Make sure the sub-domain is in the current domain
list($d, $s) = explode(';', $vars['sub_domain']);
if (trim($d) != $vars['domain']) {
$errors[] = array(
'module' => 'm_oci',
'message' => _('sub-domain does not belong to selected domain'),
'data' => array(
'sub_domain' => $vars['sub_domain'],
'domain' => $vars['domain'],
'd' => $d,
's' => $s,
),
);
}
}
if ($vars['db_name'] == '*new*') {
if (!preg_match("#^[0-9a-z]*$#", $vars['new_db_name'])) {
$error[] = array(
'module' => 'm_oci',
'message' => _('new_database_name can only contain letters and numbers'),
);
$msg->raise("ERROR", "mysql", _("Database name can contain only letters and numbers"));
return false;
}
$len=variable_get("sql_max_database_length", 64);
if (strlen($vars['db_name']) > $len) {
$error[] = array(
'module' => 'm_oci',
'message' => _('new_database_name cannot exceed character length') . ': ' . $len,
);
}
$db->query("SELECT * FROM db WHERE db= ? ;", array($dbname));
if ($db->num_rows()) {
$error[] = array(
'module' => 'm_oci',
'message' => _('new_database_name already exists'),
);
}
}
$vals = $hooks->invoke('hook_oci_form_validate', array($app, $vars));
foreach ($vals as $v) {
if ($v && is_array($v) && !is_empty($v)) {
$errors = $errors + $v;
}
}
return $errors;
}
/**
* Implements hook_oci_form_validate.
*/
function hook_oci_form_validate($app, $vars) {
$errors = array();
// @TODO Drupal
// @TODO Wordpress
return $errors;
}
/**
* Installs an application.
*/
function install($app, $vars) {
global $hooks, $dom, $mysql, $msg, $mem, $db, $cuid, $L_ALTERNC_HTML;
$r = '';
// Add new domain if necessary.
if ($vars['domain'] == '*new*') {
$dom->lock();
// @TODO don't force dns to on enabled.
if (!$dom->add_domain($vars['new_domain_name'], 1)) {
$msg->raise('ERROR', '....');
return '';
} else {
$vars['domain'] = $vars['new_domain_name'];
unset($vars['new_domain_name']);
}
$dom->unlock();
}
// Add new sub-domain if necessary.
if ($vars['sub_domain'] == '*new*') {
// @TODO special case: handle new_sub_domain_name was a default domain graceully.
$dom->lock();
if (!$dom->set_sub_domain($vars['domain'], $vars['new_sub_domain_name'],
$vars['new_sub_domain_type'], $vars['new_sub_domain_path'])) {
$msg->raise('ERROR', '......');
return '';
} else {
$vars['sub_domain'] = $vars['new_sub_domain_name'];
unset($vars['new_sub_domain_name']);
unset($vars['new_sub_domain_path']);
unset($vars['new_sub_domain_type']);
}
$dom->unlock();
} else {
list($d, $s) = explode(';', $vars['sub_domain']);
if ($d != $vars['domain']) {
$msg->raise('ERROR', 'm_oci', 'sub_domai %s doesn\'t belong to domain %s',
array($vars['sub_domain'], $vars['domain']));
}
$vars['sub_domain'] = $s;
}
// Add database if necessary.
if ($vars['db_name'] == '*new*') {
$login = $mem->user['login'];
if(!$mysql->add_db("${login}_${vars['new_db_name']}")) {
$msg->raise('ERROR', '....');
return '';
} else {
$vars['db_name'] = "${login}_${vars['new_db_name']}";
unset($vars['new_db_name']);
}
}
// Fill out variables to pass on to the install hooks.
$db->query("SELECT dbu.name,dbu.password, dbs.host FROM dbusers dbu, db_servers dbs, membres m WHERE dbu.uid= ? and enable='ACTIVATED' and dbs.id=m.db_server_id and m.uid= ? and dbu.name = ?;", array($cuid, $cuid, $vars['db_name']));
if (!$db->num_rows()) {
$msg->raise('ERROR', 'm_oci', _('Unable to get database information for user "%s", db "%s"'), array($cuid, $vars['db_name']));
return '';
}
$db->next_record();
$vars['db_user'] = $db->Record['name'];
$vars['db_pass'] = $db->Record['password'];
$vars['db_host'] = $db->Record['host'];
$vars['db_port'] = '3306'; // Seems to be hardcoded in AlternC
$dom->lock();
$domain_info = $dom->get_domain_all($vars['domain']);
$dom->unlock();
$vars['url'] = ($vars['sub_domain']) ? $vars['sub_domain'] . '.' : '';
$vars['url'] .= $vars['domain'];
$msg->raise('INFO', 'm_oci', 'Domain info: %s', print_r($domain_info, TRUE));
foreach ($domain_info['sub'] as $delta => $sub_info) {
if($sub_info['name'] != $vars['sub_domain']) {
continue;
}
$vars['path'] = $sub_info['dest'];
}
$login = $mem->user['login'];
$vars['path'] = $L_ALTERNC_HTML . '/' . substr($login, 0, 1) . '/' . $login . $vars['path'];
// db_user,pass,host,port,name ; url,path
$msg->raise('INFO', 'm_oci', 'Invoking hook_oci_install for app %s with args %s',
array($app, print_r($vars, TRUE)));
$vals = $hooks->invoke('hook_oci_install', array($app, $vars));
foreach ($vals as $v) {
$r .= $v;
}
$vals = $hooks->invoke('hook_oci_post_install', array($app, $hook_vars));
foreach ($vals as $v) {
$r .= $v;
}
return $r;
}
/**
* Implements hook_oci_install.
*/
function hook_oci_install($app, $vars) {
if ($app == 'drupal') {
$r .= $this->_install_drupal($app, $vars);
} elseif ($app == 'wordpress') {
$r .= $this->_install_wordpress($app, $vars);
}
return '';
}
/**
* Install drupal
*/
private function _install_drupal($app, $vars) {
global $L_ALTERNC_DRUSH_BIN, $msg;
$si_args = array(
'--site-mail' => $vars['drupal_site_mail'],
'--site-name' => $vars['drupal_title'],
'--sites-subdir' => $vars['drupal_site_name'],
'--root' => $vars['path'],
'--account-mail' => $vars['drupal_admin_mail'],
'--account-name' => $vars['drupal_admin_name'],
'--db-prefix' => $vars['db_prefix'],
'--db-url' => "mysql://${vars['db_user']}:${vars['db_pass']}@${vars['db_host']}:${vars['db_port']}/${vars['db_name']}",
);
$r = '';
if ($vars['drupal_makefile']) {
$cmd = sprintf("$_ALTERNC_DRUSH_BIN make --concurrency=5 %s %s",
$vars['drupal_makefile'],
$vars['path']);
$msg->raise('INFO', 'm_oci', 'Running command: %s', array($cmd));
$r .= shell_exec($cmd . ' 2>&1');
}
if ($vars['drupal_core_version']) {
$version = 'drupal-' . $vars['drupal_core_version'];
$cmd = sprintf("$L_ALTERNC_DRUSH_BIN dl %s %s %s --yes",
escapeshellarg($version),
'--destination=' . escapeshellarg($vars['path']),
'--drupal-project-rename="."'
);
$msg->raise('INFO', 'm_oci', 'Running command: %s', array($cmd));
$r .= shell_exec($cmd . ' 2>&1');
}
$si_arg = '';
foreach ($si_args as $name => $value) {
if (!$value) {
continue;
}
$si_arg .= "$name=" . escapeshellarg($value) . ' ';
}
$si_arg .= ' --yes'; // . ' ' . escapeshellarg($vars['drupal_site_name']);
$msg->raise('INFO', 'm_oci', _('Starting Drupal installation with arguments: %s'), array($si_arg));
// @FIXME This seems to use an insane about of memory and gets OOM killed.
$r .= shell_exec("$L_ALTERNC_DRUSH_BIN si $si_arg 2>&1");
return $r;
}
/**
* Install wordpress
*/
private function _install_wordpress($app, $vars) {
global $L_ALTERNC_WP_BIN, $msg;
$dl = array(
'--path' => $vars['path'],
'--locale' => $vars['wordpress_locale'],
);
$dl_arg = '';
foreach ($dl as $n => $v) {
if ($v) {
$dl_arg .= " $n=" . escapeshellarg($v);
}
}
$msg->raise('INFO', 'm_oci', 'Running command: %s',
array("$L_ALTERNC_WP_BIN core download $dl_arg"));
$r = shell_exec("$L_ALTERNC_WP_BIN core download $dl_arg 2>&1");
$cfg = array(
'--path' => $vars['path'],
'--dbname' => $vars['db_name'],
'--dbuser' => $vars['db_user'],
'--dbhost' => $vars['db_host'],
'--dbpass' => $vars['db_pass'],
'--locale' => $vars['wordpress_locale'],
);
$cfg_arg = '';
foreach ($cfg as $n => $v) {
if (!$v) {
continue;
}
$cfg_arg .= ' ' . "$n=" . escapeshellarg($v);
}
$msg->raise('INFO', 'm_oci', 'Running command: %s',
array("$L_ALTERNC_WP_BIN config create $cfg_arg"));
$r .= shell_exec("$L_ALTERNC_WP_BIN config create $cfg_arg 2>&1");
$inst = array(
'--path' => $vars['path'],
'--url' => $vars['url'],
'--title' => $vars['wordpress_title'],
'--admin_email' => $vars['wordpress_admin_mail'],
'--admin_name' => $vars['wordpress_admin_name'],
);
$inst_arg = '';
foreach ($inst as $n => $v) {
if (!$v) {
continue;
}
$inst_arg .= ' ' . "$n=" . escapeshellarg($v);
}
$msg->raise('INFO', 'm_oci', 'Running command: %s',
array("$L_ALTERNC_WP_BIN core install $inst_arg"));
$r .= shell_exec("$L_ALTERNC_WP_BIN core install $inst_arg 2>&1");
return $r;
}
}