Skip to content

Commit

Permalink
Disallowed access to default site by default. Added database variable…
Browse files Browse the repository at this point in the history
… alter support. Added additional environment var support.
  • Loading branch information
dl-unleashed-technologies committed Jan 4, 2022
1 parent d403f15 commit 798ba18
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 23 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ Updates should follow the [Keep a CHANGELOG](https://keepachangelog.com/) princi

## [Unreleased][unreleased]

## [0.1.10] - 2022-01-04

### Changed

- Disallowed access to `default` site in a multi-site install by default.
- Added support for `$database` variable alteration.
- Added support for `FILE_PUBLIC_PATH` environment variable.
- Added support for `FILE_PRIVATE_PATH` environment variable.
- Added support for `FILE_TEMP_PATH` environment variable.
- Added support for `CONFIG_SYNC_PATH` environment variable.

## [0.1.9] - 2021-12-29

### Fixed
Expand Down Expand Up @@ -70,7 +81,8 @@ Updates should follow the [Keep a CHANGELOG](https://keepachangelog.com/) princi

**Initial release!**

[unreleased]: https://github.com/unleashedtech/dotenv-drupal/compare/0.1.9...main
[unreleased]: https://github.com/unleashedtech/dotenv-drupal/compare/0.1.10...main
[0.1.10]: https://github.com/unleashedtech/dotenv-drupal/compare/0.1.9...0.1.10
[0.1.9]: https://github.com/unleashedtech/dotenv-drupal/compare/0.1.8...0.1.9
[0.1.8]: https://github.com/unleashedtech/dotenv-drupal/compare/0.1.7...0.1.8
[0.1.7]: https://github.com/unleashedtech/dotenv-drupal/compare/0.1.6...0.1.7
Expand Down
74 changes: 65 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,24 @@ $databases = $dotenv->getDatabases();
$settings = $dotenv->getSettings();
```

##### Multi-Site Drupal
Many multi-site installations leave the `default` site unused. If this is the
case, you can use the `default` settings file for base configuration in the
`settings.php` file for each site.
##### Conditional Logic
If conditional logic is required for a given site, such logic is still supported.
This package will auto-load various `settings.{{environment}}.php`,
`config.{{environment}}.php` or `databases.{{environment}}.php` files, if they exist.
For instance, if you need to set a database prefix for staging, you can create
`databases.staging.php`:

In your relevant environment file(s), leave the "database" (e.g. "path")
empty to allow automatic database name selection based on the site name.
```php
<?php
$databases['default']['default']['prefix'] = 'foo_';
```

Each included file only has the related variable in scope
(e.g. `config.dev.php` only has `$config` in scope).

##### Multi-Site Drupal
You can use the `default` settings file to provide base configuration for
a multi-site install:

```php
<?php
Expand All @@ -56,9 +67,20 @@ $dotenv->setDatabaseName('foo');
require __DIR__ . '/../default/settings.php';
```

If conditional logic is required for a given site, such logic is still supported.
This package will auto-load various `settings.{{environment}}.php` or
`config.{{environment}}.php` files, if they exist.
###### Using the Multi-Site Default Site
If you need to use the `default` site as part of your multi-site install,
you can allow it by calling the `DotEnv::setMultiSiteDefaultSiteAllowed` method
in `default/settings.php`:

```php
<?php
use UnleashedTech\Drupal\Dotenv\Dotenv;
$dotenv = $dotenv ?? new Dotenv();
$dotenv->setMultiSiteDefaultSiteAllowed();
$config = $dotenv->getConfig();
$databases = $dotenv->getDatabases();
$settings = $dotenv->getSettings();
```

###### Sites Files
This package also provides functionality to configure Drupal's `$sites` variable
Expand Down Expand Up @@ -86,6 +108,10 @@ For production environments, environment variables should ideally be defined via
configuration.

* [DATABASE_URL](#database_url)
* [FILE_PUBLIC_PATH](#file_public_path)
* [FILE_PRIVATE_PATH](#file_private_path)
* [FILE_TEMP_PATH](#file_temp_path)
* [CONFIG_SYNC_PATH](#config_sync_path)
* [DOMAINS](#domains)
* [SITES](#sites)
* [SOLR_URL](#solr_url)
Expand All @@ -110,6 +136,36 @@ For multi-site installations, do _not_ specify a database name in the `DATABASE_
DATABASE_URL=mysql://foo:bar@host:3306
```

#### FILE_PUBLIC_PATH
Allows you to override the default `$settings['file_public_path']` value:

```dotenv
FILE_PUBLIC_PATH=sites/all/files
```

Drupal expects this path to be _relative_ to `DRUPAL_ROOT`.

#### FILE_PRIVATE_PATH
Allows you to override the default `$settings['file_private_path']` value:

```dotenv
FILE_PRIVATE_PATH=/private
```

#### FILE_TEMP_PATH
Allows you to override the default `$settings['file_temp_path']` value:

```dotenv
FILE_TEMP_PATH=/tmp
```

#### CONFIG_SYNC_PATH
Allows you to override the default `$settings['config_sync_path']` value:

```dotenv
CONFIG_SYNC_PATH=/sync
```

#### DOMAINS
A CSV list of domains used by the given environment:

Expand Down
76 changes: 63 additions & 13 deletions src/Dotenv.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ class Dotenv
*/
private string $siteName = 'default';

/**
* @var bool Whether the default site is allowed in a multi-site configuration.
*/
private bool $isMultiSiteDefaultSiteAllowed = FALSE;

/**
* The class constructor.
*/
Expand Down Expand Up @@ -71,19 +76,33 @@ public function getEnvironmentName(): string
}

/**
* Decorates the given data with data of the same type defined in PHP files.
* Alters the given data with data of the same type defined in PHP files.
*
* @param $data
* The data to alter.
* @param $type
* The type of data being altered (e.g. settings, config, databases).
*/
private function decorate(&$data, $type): void
private function alter(&$data, $type): void
{
$$type = &$data;
$file = DRUPAL_ROOT . '/sites/' . $this->getSiteName() . '/' .

// Allow alteration via the `default` directory.
$file = DRUPAL_ROOT . '/sites/default/' .
$type . '.' . $this->getEnvironmentName() . '.php';
if (file_exists($file)) {
include $file;
}

// Allow alteration via non-`default` directories.
$siteName = $this->getSiteName();
if ($siteName !== 'default') {
$file = DRUPAL_ROOT . '/sites/' . $siteName . '/' .
$type . '.' . $this->getEnvironmentName() . '.php';
if (file_exists($file)) {
include $file;
}
}
}

/**
Expand Down Expand Up @@ -139,14 +158,14 @@ public function getConfig(): array
];
break;
}
$this->decorate($config, 'config');
$this->alter($config, 'config');
return $config;
}

public function getDatabases(): array
{
$db_url = parse_url($_SERVER['DATABASE_URL']);
return [
$databases = [
'default' =>
[
'default' =>
Expand All @@ -162,22 +181,47 @@ public function getDatabases(): array
],
],
];
$this->alter($databases, 'databases');
return $databases;
}

public function getDatabaseName(): ?string
public function getDatabaseName(): string
{
if (isset($this->databaseName)) {
return $this->databaseName;
}
$result = parse_url($_SERVER['DATABASE_URL'], PHP_URL_PATH);
return (FALSE === $result || '/' === $result) ? $this->getSiteName() : substr($result, 1);
if (NULL === $result || trim($result) === '/') {
// Multi-site configuration detected. Use the site name.
$result = $this->getSiteName();
if ($result === 'default' && !$this->isMultiSiteDefaultSiteAllowed()) {
header("HTTP/1.1 401 Unauthorized");
die('Unauthorized');
}
} else {
$result = substr($result, 1);
}
if (NULL === $result || preg_replace('/[^a-z0-9_]/', '', $result) === '') {
throw new \UnexpectedValueException('Database name could not be computed.');
}
return $result;
}

function setDatabaseName(string $database)
public function setDatabaseName(string $database): void
{
$this->databaseName = $database;
}

public function isMultiSiteDefaultSiteAllowed(): bool
{
return $this->isMultiSiteDefaultSiteAllowed;
}

public function setMultiSiteDefaultSiteAllowed(bool $allowed = TRUE): void
{
$this->isMultiSiteDefaultSiteAllowed = $allowed;
}

public function getSettings(): array
{
$envName = $this->getEnvironmentName();
Expand All @@ -192,6 +236,7 @@ public function getSettings(): array
$settings['config_sync_directory'] = $this->getConfigSyncPath();
$settings['file_public_path'] = $this->getPublicFilePath();
$settings['file_private_path'] = $this->getPrivateFilePath();
$settings['file_temp_path'] = $this->getTemporaryFilePath();
if (isset($_SERVER['HASH_SALT'])) {
$settings['hash_salt'] = $_SERVER['HASH_SALT'];
}
Expand Down Expand Up @@ -221,7 +266,7 @@ public function getSettings(): array
$this->getAppPath() . '/sites/' . $envName . '.services.yml',
];
}
$this->decorate($settings, 'settings');
$this->alter($settings, 'settings');
return $settings;
}

Expand Down Expand Up @@ -253,19 +298,24 @@ public function getProjectPath(): string
return dirname(DRUPAL_ROOT, 1);
}

public function getPublicFilePath(): string
{
return $_SERVER['FILE_PUBLIC_PATH'] ?? 'sites/' . $this->getSiteName() . '/files';
}

public function getPrivateFilePath(): string
{
return dirname(DRUPAL_ROOT, 1);
return $_SERVER['FILE_PRIVATE_PATH'] ?? $this->getProjectPath() . '/drupal/private_files';
}

public function getPublicFilePath(): string
public function getTemporaryFilePath(): string
{
return 'sites/' . $this->getSiteName() . '/files';
return $_SERVER['FILE_TEMP_PATH'] ?? $this->getProjectPath() . '/drupal/temporary_files';
}

public function getConfigSyncPath(): string
{
return $this->getProjectPath() . '/drupal/config/sync';
return $_SERVER['CONFIG_SYNC_PATH'] ?? $this->getProjectPath() . '/drupal/config/sync';
}

}

0 comments on commit 798ba18

Please sign in to comment.