Oliver's answer is appropriate, but here's if you want to do it programmatically (by example for copying a setup to create a new instance on a same domain):
/**
* Update the access file of the new sub-domain. Otherwise the user will
* constantly be redirected to the setup.
*
* @param $errorMessage String array to return the error message.
* @param $name String name of the subdomain to update.
*
* @return Boolean
*/
private function updateAccessFile(&$errorMessage, $name){
$success = false;
$fileContent = file_get_contents(realpath(dirname(__FILE__)) . '/../../' . $name . "/.htaccess");
if ($fileContent !== false){
$filcontent = str_replace("setup", $name, $fileContent);
$success = boolval(file_put_contents(realpath(dirname(__FILE__)) . '/../../' . $name . "/.htaccess", $filcontent));
}
if (!$success){
$errorMessage[] = parent::getErrorMessage("SUBDOMAIN_CREATION_CONF_FILE_ERR", "We are not able to update the prestashop main access file.");
}
return $success;
}
/**
* Update the configuration file with the configuration for the new subdomain
* in order to access the sub-domain affiliated database.
*
* @param $errorMessage String array to return the error message.
* @param $name String name of the subdomain to update.
*
* @return Boolean
*/
private function updateConfigurationFile(&$errorMessage, $name){
$counter = 0;
$reader = fopen(realpath(dirname(__FILE__)) . '/../../' . $name .'/config/settings.inc.php', 'r');
$writter = fopen(realpath(dirname(__FILE__)) . '/../../' . $name .'/config/temp.txt', 'w');
while (!feof($reader)) {
$line = fgets($reader);
if (strpos(strtoupper($line), '_DB_SERVER_') !== false) {
$line = "define('_DB_SERVER_', '127.0.0.1');\n";
$counter++;
}
elseif (strpos(strtoupper($line), '_DB_NAME_') !== false) {
$line = "define('_DB_NAME_', '" . $name . "');\n";
$counter++;
}
elseif (strpos(strtoupper($line), '_COOKIE_KEY_') !== false and !empty($this->fetchEncryptionKey())) {
$line = "define('_COOKIE_KEY_', '" . $this->saltKey . "');\n";
$counter++;
}
fputs($writter, $line);
}
fclose($reader);
fclose($writter);
if ($counter > 0){
rename(realpath(dirname(__FILE__)) . '/../../' . $name .'/config/temp.txt', realpath(dirname(__FILE__)) . '/../../' . $name .'/config/settings.inc.php');
}
else{
unlink(realpath(dirname(__FILE__)) . '/../../' . $name .'/config/temp.txt');
}
if ($counter !== 3){
$errorMessage[] = parent::getErrorMessage("SUBDOMAIN_CREATION_CONF_FILE_ERR", "We are not able to update prestashop configuration file.");
}
return (empty($errorMessage) ? true : false);
}
And a stored procedure for the database:
DELIMITER $$
CREATE PROCEDURE setupStore(IN shopName VARCHAR(50), IN domain VARCHAR(50), IN encryptionKey CHAR(56), OUT success BOOLEAN)
BEGIN
DECLARE fail BOOLEAN DEFAULT false;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET fail = true;
START TRANSACTION;
SET success = false;
SET @shop = shopName;
SET @domain = domain;
SET @uri = CONCAT('/', shopName, '/');
SET @query = 'UPDATE ps_shop s INNER JOIN ps_shop_url su ON s.id_shop = su.id_shop SET s.name=?, su.domain=?, su.domain_ssl=?, su.physical_uri=? WHERE s.id_shop=1';
PREPARE statement FROM @query;
EXECUTE statement USING @shop, @domain, @domain, @uri;
SET @query = CONCAT('UPDATE ps_configuration SET value= ? where name=', QUOTE('PS_SHOP_DOMAIN'), 'OR name=', QUOTE('PS_SHOP_DOMAIN_SSL'));
PREPARE statement FROM @query;
EXECUTE statement USING @domain;
SET @query = CONCAT('UPDATE ps_configuration SET value= ? where name=', QUOTE('PS_SHOP_NAME'));
PREPARE statement FROM @query;
EXECUTE statement USING @shop;
DELETE FROM pc_import_config;
SET @query = 'INSERT INTO pc_import_config(cookie_key) VALUES(?)';
SET @key = encryptionKey;
PREPARE statement FROM @query;
EXECUTE statement USING @key;
IF fail THEN
ROLLBACK;
ELSE
COMMIT;
SET success = true;
END IF;
DEALLOCATE PREPARE statement;
END$$
DELIMITER ;
Note: pc_import_config is not a real prestashop table, I use that table to keep in memory the encryption_key used during data import from the DataImporter (abstract class for data import from different data sources into different setups) to use it in the subDomainManager (abstract class for creating instance of subdomains from different base setup and then managing them).
Jonathan Parent-Lévesque from Montreal