Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2894245
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
44 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/scripts/__init_env__.php b/scripts/__init_env__.php
index 8bdedcf92a..cf28583ea3 100644
--- a/scripts/__init_env__.php
+++ b/scripts/__init_env__.php
@@ -1,51 +1,53 @@
<?php
/*
- * Copyright 2011 Facebook, Inc.
+ * Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
$include_path = ini_get('include_path');
-ini_set('include_path', $include_path.':'.dirname(__FILE__).'/../../');
+ini_set(
+ 'include_path',
+ $include_path.PATH_SEPARATOR.dirname(__FILE__).'/../../');
require_once dirname(dirname(__FILE__)).'/conf/__init_conf__.php';
$env = isset($_SERVER['PHABRICATOR_ENV'])
? $_SERVER['PHABRICATOR_ENV']
: getenv('PHABRICATOR_ENV');
if (!$env) {
echo "Define PHABRICATOR_ENV before running this script.\n";
exit(1);
}
$conf = phabricator_read_config_file($env);
$conf['phabricator.env'] = $env;
phutil_require_module('phabricator', 'infrastructure/env');
PhabricatorEnv::setEnvConfig($conf);
phutil_load_library('arcanist/src');
foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
phutil_load_library($library);
}
PhutilErrorHandler::initialize();
PhabricatorEventEngine::initialize();
$tz = PhabricatorEnv::getEnvConfig('phabricator.timezone');
if ($tz) {
date_default_timezone_set($tz);
}
diff --git a/scripts/__init_script__.php b/scripts/__init_script__.php
index 1be63fd2cc..e2551149c3 100644
--- a/scripts/__init_script__.php
+++ b/scripts/__init_script__.php
@@ -1,68 +1,67 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
$include_path = ini_get('include_path');
-ini_set('include_path', $include_path.':'.dirname(__FILE__).'/../../');
+ini_set(
+ 'include_path',
+ $include_path.PATH_SEPARATOR.dirname(__FILE__).'/../../');
@include_once 'libphutil/scripts/__init_script__.php';
if (!@constant('__LIBPHUTIL__')) {
echo "ERROR: Unable to load libphutil. Update your PHP 'include_path' to ".
"include the parent directory of libphutil/.\n";
exit(1);
}
phutil_load_library(dirname(__FILE__).'/../src/');
// NOTE: This is dangerous in general, but we know we're in a script context and
// are not vulnerable to CSRF.
AphrontWriteGuard::allowDangerousUnguardedWrites(true);
-$include_path = ini_get('include_path');
-ini_set('include_path', $include_path.':'.dirname(__FILE__).'/../../');
-
require_once dirname(dirname(__FILE__)).'/conf/__init_conf__.php';
$env = isset($_SERVER['PHABRICATOR_ENV'])
? $_SERVER['PHABRICATOR_ENV']
: getenv('PHABRICATOR_ENV');
if (!$env) {
echo "Define PHABRICATOR_ENV before running this script.\n";
exit(1);
}
$conf = phabricator_read_config_file($env);
$conf['phabricator.env'] = $env;
phutil_require_module('phabricator', 'infrastructure/env');
PhabricatorEnv::setEnvConfig($conf);
phutil_load_library('arcanist/src');
foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
phutil_load_library($library);
}
PhutilErrorHandler::initialize();
PhabricatorEventEngine::initialize();
$tz = PhabricatorEnv::getEnvConfig('phabricator.timezone');
if ($tz) {
date_default_timezone_set($tz);
}
diff --git a/src/infrastructure/setup/PhabricatorSetup.php b/src/infrastructure/setup/PhabricatorSetup.php
index 02b5d0a0f4..4eba25c3f6 100644
--- a/src/infrastructure/setup/PhabricatorSetup.php
+++ b/src/infrastructure/setup/PhabricatorSetup.php
@@ -1,816 +1,816 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorSetup {
public static function runSetup() {
header("Content-Type: text/plain");
self::write("PHABRICATOR SETUP\n\n");
// Force browser to stop buffering.
self::write(str_repeat(' ', 2048));
usleep(250000);
self::write("This setup mode will guide you through setting up your ".
"Phabricator configuration.\n");
self::writeHeader("CORE CONFIGURATION");
// NOTE: Test this first since other tests depend on the ability to
// execute system commands and will fail if safe_mode is enabled.
$safe_mode = ini_get('safe_mode');
if ($safe_mode) {
self::writeFailure();
self::write(
"Setup failure! You have 'safe_mode' enabled. Phabricator will not ".
"run in safe mode, and it has been deprecated in PHP 5.3 and removed ".
"in PHP 5.4.\n");
return;
} else {
self::write(" okay PHP's deprecated 'safe_mode' is disabled.\n");
}
// NOTE: Also test this early since we can't include files from other
// libraries if this is set strictly.
$open_basedir = ini_get('open_basedir');
if ($open_basedir) {
// 'open_basedir' restricts which files we're allowed to access with
// file operations. This might be okay -- we don't need to write to
// arbitrary places in the filesystem -- but we need to access certain
// resources. This setting is unlikely to be providing any real measure
// of security so warn even if things look OK.
try {
phutil_require_module('phutil', 'utils');
$open_libphutil = true;
} catch (Exception $ex) {
$message = $ex->getMessage();
self::write("Unable to load modules from libphutil: {$message}\n");
$open_libphutil = false;
}
try {
phutil_require_module('arcanist', 'workflow/base');
$open_arcanist = true;
} catch (Exception $ex) {
$message = $ex->getMessage();
self::write("Unable to load modules from Arcanist: {$message}\n");
$open_arcanist = false;
}
$open_urandom = @fopen('/dev/urandom', 'r');
if (!$open_urandom) {
self::write("Unable to open /dev/urandom!\n");
}
try {
$tmp = new TempFile();
file_put_contents($tmp, '.');
$open_tmp = @fopen((string)$tmp, 'r');
} catch (Exception $ex) {
$message = $ex->getMessage();
$dir = sys_get_temp_dir();
self::write("Unable to open temp files from '{$dir}': {$message}\n");
$open_tmp = false;
}
if (!$open_urandom || !$open_tmp || !$open_libphutil || !$open_arcanist) {
self::writeFailure();
self::write(
"Setup failure! Your server is configured with 'open_basedir' in ".
"php.ini which prevents Phabricator from opening files it needs to ".
"access. Either make the setting more permissive or remove it. It ".
"is unlikely you derive significant security benefits from having ".
"this configured; files outside this directory can still be ".
"accessed through system command execution.");
return;
} else {
self::write(
"[WARN] You have an 'open_basedir' configured in your php.ini. ".
"Although the setting seems permissive enough that Phabricator ".
"will run properly, you may run into problems because of it. It is ".
"unlikely you gain much real security benefit from having it ".
"configured, because the application can still access files outside ".
"the 'open_basedir' by running system commands.\n");
}
} else {
self::write(" okay 'open_basedir' is not set.\n");
}
if (!PhabricatorEnv::getEnvConfig('security.alternate-file-domain')) {
self::write(
"[WARN] You have not configured 'security.alternate-file-domain'. ".
"This makes your installation vulnerable to attack. Make sure you ".
"read the documentation for this parameter and understand the ".
"consequences of leaving it unconfigured.\n");
}
$path = getenv('PATH');
if (empty($path)) {
self::writeFailure();
self::write(
"Setup failure! The environmental \$PATH variable is empty. ".
"Phabricator needs to execute system commands like 'svn', 'git', ".
"'hg', and 'diff'. Set up your webserver so that it passes a valid ".
"\$PATH to the PHP process.\n\n");
if (php_sapi_name() == 'fpm-fcgi') {
self::write(
"You're running php-fpm, so the easiest way to do this is to add ".
"this line to your php-fpm.conf:\n\n".
" env[PATH] = /usr/local/bin:/usr/bin:/bin\n\n".
"Then restart php-fpm.\n");
}
return;
} else {
self::write(" okay \$PATH is nonempty.\n");
}
self::write("[OKAY] Core configuration OKAY.\n");
self::writeHeader("REQUIRED PHP EXTENSIONS");
$extensions = array(
'mysql',
'hash',
'json',
'openssl',
'mbstring',
'iconv',
// There is a chance we might not need this, but some configurations (like
// Amazon SES) will require it. Just mark it 'required' since it's widely
// available and relatively core.
'curl',
);
foreach ($extensions as $extension) {
$ok = self::requireExtension($extension);
if (!$ok) {
self::writeFailure();
self::write("Setup failure! Install PHP extension '{$extension}'.");
return;
}
}
list($err, $stdout, $stderr) = exec_manual('which php');
if ($err) {
self::writeFailure();
self::write("Unable to locate 'php' on the command line from the web ".
"server. Verify that 'php' is in the webserver's PATH.\n".
" err: {$err}\n".
"stdout: {$stdout}\n".
"stderr: {$stderr}\n");
return;
} else {
self::write(" okay PHP binary found on the command line.\n");
$php_bin = trim($stdout);
}
// NOTE: In cPanel + suphp installs, 'php' may be the PHP CGI SAPI, not the
// PHP CLI SAPI. proc_open() will pass the environment to the child process,
// which will re-execute the webpage (causing an infinite number of
// processes to spawn). To test that the 'php' binary is safe to execute,
// we call php_sapi_name() using "env -i" to wipe the environment so it
// doesn't execute another reuqest if it's the wrong binary. We can't use
// "-r" because php-cgi doesn't support that flag.
$tmp_file = new TempFile('sapi.php');
Filesystem::writeFile($tmp_file, '<?php echo php_sapi_name();');
list($err, $stdout, $stderr) = exec_manual(
'/usr/bin/env -i %s -f %s',
$php_bin,
$tmp_file);
if ($err) {
self::writeFailure();
self::write("Unable to execute 'php' on the command line from the web ".
"server.\n".
" err: {$err}\n".
"stdout: {$stdout}\n".
"stderr: {$stderr}\n");
return;
} else {
self::write(" okay PHP is available from the command line.\n");
$sapi = trim($stdout);
if ($sapi != 'cli') {
self::writeFailure();
self::write(
"The 'php' binary on this system uses the '{$sapi}' SAPI, but the ".
"'cli' SAPI is expected. Replace 'php' with the php-cli SAPI ".
"binary, or edit your webserver configuration so the first 'php' ".
"in PATH is the 'cli' SAPI.\n\n".
"If you're running cPanel with suphp, the easiest way to fix this ".
"is to add '/usr/local/bin' before '/usr/bin' for 'env_path' in ".
"suconf.php:\n\n".
' env_path="/bin:/usr/local/bin:/usr/bin"'.
"\n\n");
return;
} else {
self::write(" okay 'php' is CLI SAPI.\n");
}
}
$root = dirname(phutil_get_library_root('phabricator'));
// On RHEL6, doing a distro install of pcntl makes it available from the
// CLI binary but not from the Apache module. This isn't entirely
// unreasonable and we don't need it from Apache, so do an explicit test
// for CLI availability.
list($err, $stdout, $stderr) = exec_manual(
- '%s/scripts/setup/pcntl_available.php',
- $root);
+ 'php %s',
+ "{$root}/scripts/setup/pcntl_available.php");
if ($err) {
self::writeFailure();
self::write("Unable to execute scripts/setup/pcntl_available.php to ".
"test for the availability of pcntl from the CLI.\n".
" err: {$err}\n".
"stdout: {$stdout}\n".
"stderr: {$stderr}\n");
return;
} else {
if (trim($stdout) == 'YES') {
self::write(" okay pcntl is available from the command line.\n");
self::write("[OKAY] All extensions OKAY\n");
} else {
self::write(" warn pcntl is not available!\n");
self::write("[WARN] *** WARNING *** pcntl extension not available. ".
"You will not be able to run daemons.\n");
}
}
self::writeHeader("GIT SUBMODULES");
if (!Filesystem::pathExists($root.'/.git')) {
self::write(" skip Not a git clone.\n\n");
} else {
list($info) = execx(
'(cd %s && git submodule status)',
$root);
foreach (explode("\n", rtrim($info)) as $line) {
$matches = null;
if (!preg_match('/^(.)([0-9a-f]{40}) (\S+)(?: |$)/', $line, $matches)) {
self::writeFailure();
self::write(
"Setup failure! 'git submodule' produced unexpected output:\n".
$line);
return;
}
$status = $matches[1];
$module = $matches[3];
switch ($status) {
case '-':
case '+':
case 'U':
self::writeFailure();
self::write(
"Setup failure! Git submodule '{$module}' is not up to date. ".
"Run:\n\n".
" cd {$root} && git submodule update --init\n\n".
"...to update submodules.");
return;
case ' ':
self::write(" okay Git submodule '{$module}' up to date.\n");
break;
default:
self::writeFailure();
self::write(
"Setup failure! 'git submodule' reported unknown status ".
"'{$status}' for submodule '{$module}'. This is a bug; report ".
"it to the Phabricator maintainers.");
return;
}
}
}
self::write("[OKAY] All submodules OKAY.\n");
self::writeHeader("BASIC CONFIGURATION");
$env = PhabricatorEnv::getEnvConfig('phabricator.env');
if ($env == 'production' || $env == 'default' || $env == 'development') {
self::writeFailure();
self::write(
"Setup failure! Your PHABRICATOR_ENV is set to '{$env}', which is ".
"a Phabricator environmental default. You should create a custom ".
"environmental configuration instead of editing the defaults ".
"directly. See this document for instructions:\n");
self::writeDoc('article/Configuration_Guide.html');
return;
} else {
$host = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
$host_uri = new PhutilURI($host);
$protocol = $host_uri->getProtocol();
$allowed_protocols = array(
'http' => true,
'https' => true,
);
if (empty($allowed_protocols[$protocol])) {
self::writeFailure();
self::write(
"You must specify the protocol over which your host works (e.g.: ".
"\"http:// or https://\")\nin your custom config file.\nRefer to ".
"'default.conf.php' for documentation on configuration options.\n");
return;
}
if (preg_match('/.*\/$/', $host)) {
self::write(" okay phabricator.base-uri protocol\n");
} else {
self::writeFailure();
self::write(
"You must add a trailing slash at the end of the host\n(e.g.: ".
"\"http://phabricator.example.com/ instead of ".
"http://phabricator.example.com\")\nin your custom config file.".
"\nRefer to 'default.conf.php' for documentation on configuration ".
"options.\n");
return;
}
$host_domain = $host_uri->getDomain();
if (strpos($host_domain, '.') !== false) {
self::write(" okay phabricator.base-uri domain\n");
} else {
self::writeFailure();
self::write(
"You must host Phabricator on a domain that contains a dot ('.'). ".
"The current domain, '{$host_domain}', does not have a dot, so some ".
"browsers will not set cookies on it. For instance, ".
"'http://example.com/ is OK, but 'http://example/' won't work. ".
"If you are using localhost, create an entry in the hosts file like ".
"'127.0.0.1 example.com', and access the localhost with ".
"'http://example.com/'.");
return;
}
}
$timezone = nonempty(
PhabricatorEnv::getEnvConfig('phabricator.timezone'),
ini_get('date.timezone'));
if (!$timezone) {
self::writeFailure();
self::write(
"Setup failure! Your configuration fails to specify a server ".
"timezone. Either set 'date.timezone' in your php.ini or ".
"'phabricator.timezone' in your Phabricator configuration. See the ".
"PHP documentation for a list of supported timezones:\n\n".
"http://us.php.net/manual/en/timezones.php\n");
return;
} else {
self::write(" okay Timezone '{$timezone}' configured.\n");
}
self::write("[OKAY] Basic configuration OKAY\n");
$issue_gd_warning = false;
self::writeHeader('GD LIBRARY');
if (extension_loaded('gd')) {
self::write(" okay Extension 'gd' is loaded.\n");
$image_type_map = array(
'imagepng' => 'PNG',
'imagegif' => 'GIF',
'imagejpeg' => 'JPEG',
);
foreach ($image_type_map as $function => $image_type) {
if (function_exists($function)) {
self::write(" okay Support for '{$image_type}' is available.\n");
} else {
self::write(" warn Support for '{$image_type}' is not available!\n");
$issue_gd_warning = true;
}
}
} else {
self::write(" warn Extension 'gd' is not loaded.\n");
$issue_gd_warning = true;
}
if ($issue_gd_warning) {
self::write(
"[WARN] The 'gd' library is missing or lacks full support. ".
"Phabricator will not be able to generate image thumbnails without ".
"gd.\n");
} else {
self::write("[OKAY] 'gd' loaded and has full image type support.\n");
}
self::writeHeader('FACEBOOK INTEGRATION');
$fb_auth = PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
if (!$fb_auth) {
self::write(" skip 'facebook.auth-enabled' not enabled.\n");
} else {
self::write(" okay 'facebook.auth-enabled' is enabled.\n");
$app_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
$app_secret = PhabricatorEnv::getEnvConfig('facebook.application-secret');
if (!$app_id) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.auth-enabled' is true but there is no ".
"setting for 'facebook.application-id'.\n");
return;
} else {
self::write(" okay 'facebook.application-id' is set.\n");
}
if (!is_string($app_id)) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.application-id' should be a string.");
return;
} else {
self::write(" okay 'facebook.application-id' is string.\n");
}
if (!$app_secret) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.auth-enabled' is true but there is no ".
"setting for 'facebook.application-secret'.");
return;
} else {
self::write(" okay 'facebook.application-secret is set.\n");
}
self::write("[OKAY] Facebook integration OKAY\n");
}
self::writeHeader("MySQL DATABASE & STORAGE CONFIGURATION");
$conf = DatabaseConfigurationProvider::getConfiguration();
$conn_user = $conf->getUser();
$conn_pass = $conf->getPassword();
$conn_host = $conf->getHost();
$timeout = ini_get('mysql.connect_timeout');
if ($timeout > 5) {
self::writeNote(
"Your MySQL connect timeout is very high ({$timeout} seconds). ".
"Consider reducing it to 5 or below by setting ".
"'mysql.connect_timeout' in your php.ini.");
}
self::write(" okay Trying to connect to MySQL database ".
"{$conn_user}@{$conn_host}...\n");
ini_set('mysql.connect_timeout', 2);
$conn_raw = new AphrontMySQLDatabaseConnection(
array(
'user' => $conn_user,
'pass' => $conn_pass,
'host' => $conn_host,
'database' => null,
));
try {
queryfx($conn_raw, 'SELECT 1');
self::write(" okay Connection successful!\n");
} catch (AphrontQueryConnectionException $ex) {
$message = $ex->getMessage();
self::writeFailure();
self::write(
"Setup failure! MySQL exception: {$message} \n".
"Edit Phabricator configuration keys 'mysql.user', ".
"'mysql.host' and 'mysql.pass' to enable Phabricator ".
"to connect.");
return;
}
$databases = queryfx_all($conn_raw, 'SHOW DATABASES');
$databases = ipull($databases, 'Database');
$databases = array_fill_keys($databases, true);
if (empty($databases['phabricator_meta_data'])) {
self::writeFailure();
self::write(
"Setup failure! You haven't loaded the 'initialize.sql' file into ".
"MySQL. This file initializes necessary databases. See this guide for ".
"instructions:\n");
self::writeDoc('article/Configuration_Guide.html');
return;
} else {
self::write(" okay Databases have been initialized.\n");
}
$schema_version = queryfx_one(
$conn_raw,
'SELECT version FROM phabricator_meta_data.schema_version');
$schema_version = idx($schema_version, 'version', 'null');
$expect = PhabricatorSQLPatchList::getExpectedSchemaVersion();
if ($schema_version != $expect) {
self::writeFailure();
self::write(
"Setup failure! You haven't upgraded your database schema to the ".
"latest version. Expected version is '{$expect}', but your local ".
"version is '{$schema_version}'. See this guide for instructions:\n");
self::writeDoc('article/Upgrading_Schema.html');
return;
} else {
self::write(" okay Database schema are up to date (v{$expect}).\n");
}
$index_min_length = queryfx_one(
$conn_raw,
'SHOW VARIABLES LIKE %s',
'ft_min_word_len');
$index_min_length = idx($index_min_length, 'Value', 4);
if ($index_min_length >= 4) {
self::writeNote(
"MySQL is configured with a 'ft_min_word_len' of 4 or greater, which ".
"means you will not be able to search for 3-letter terms. Consider ".
"setting this in your configuration:\n".
"\n".
" [mysqld]\n".
" ft_min_word_len=3\n".
"\n".
"Then optionally run:\n".
"\n".
" REPAIR TABLE phabricator_search.search_documentfield QUICK;\n".
"\n".
"...to reindex existing documents.");
}
$max_allowed_packet = queryfx_one(
$conn_raw,
'SHOW VARIABLES LIKE %s',
'max_allowed_packet');
$max_allowed_packet = idx($max_allowed_packet, 'Value', PHP_INT_MAX);
$recommended_minimum = 1024 * 1024;
if ($max_allowed_packet < $recommended_minimum) {
self::writeNote(
"MySQL is configured with a small 'max_allowed_packet' ".
"('{$max_allowed_packet}'), which may cause some large writes to ".
"fail. Consider raising this to at least {$recommended_minimum}.");
} else {
self::write(" okay max_allowed_packet = {$max_allowed_packet}.\n");
}
$mysql_key = 'storage.mysql-engine.max-size';
$mysql_limit = PhabricatorEnv::getEnvConfig($mysql_key);
if ($mysql_limit && ($mysql_limit + 8192) > $max_allowed_packet) {
self::writeFailure();
self::write(
"Setup failure! Your Phabricator 'storage.mysql-engine.max-size' ".
"configuration ('{$mysql_limit}') must be at least 8KB smaller ".
"than your MySQL 'max_allowed_packet' configuration ".
"('{$max_allowed_packet}'). Raise the 'max_allowed_packet' in your ".
"MySQL configuration, or reduce the maximum file size allowed by ".
"the Phabricator configuration.\n");
return;
} else if (!$mysql_limit) {
self::write(" skip MySQL file storage engine not configured.\n");
} else {
self::write(" okay MySQL file storage engine configuration okay.\n");
}
$local_key = 'storage.local-disk.path';
$local_path = PhabricatorEnv::getEnvConfig($local_key);
if ($local_path) {
if (!Filesystem::pathExists($local_path) ||
!is_readable($local_path) ||
!is_writable($local_path)) {
self::writeFailure();
self::write(
"Setup failure! You have configured local disk storage but the ".
"path you specified ('{$local_path}') does not exist or is not ".
"readable or writable.\n");
if ($open_basedir) {
self::write(
"You have an 'open_basedir' setting -- make sure Phabricator is ".
"allowed to open files in the local storage directory.\n");
}
return;
} else {
self::write(" okay Local disk storage exists and is writable.\n");
}
} else {
self::write(" skip Not configured for local disk storage.\n");
}
$selector = PhabricatorEnv::getEnvConfig('storage.engine-selector');
try {
$storage_selector_exists = class_exists($selector);
} catch (Exception $ex) {
$storage_selector_exists = false;
}
if ($storage_selector_exists) {
self::write(" okay Using '{$selector}' as a storage engine selector.\n");
} else {
self::writeFailure();
self::write(
"Setup failure! You have configured '{$selector}' as a storage engine ".
"selector but it does not exist or could not be loaded.\n");
return;
}
self::write("[OKAY] Database and storage configuration OKAY\n");
self::writeHeader("OUTBOUND EMAIL CONFIGURATION");
$have_adapter = false;
$is_ses = false;
$adapter = PhabricatorEnv::getEnvConfig('metamta.mail-adapter');
switch ($adapter) {
case 'PhabricatorMailImplementationPHPMailerLiteAdapter':
$have_adapter = true;
if (!Filesystem::pathExists('/usr/bin/sendmail') &&
!Filesystem::pathExists('/usr/sbin/sendmail')) {
self::writeFailure();
self::write(
"Setup failure! You don't have a 'sendmail' binary on this system ".
"but outbound email is configured to use sendmail. Install an MTA ".
"(like sendmail, qmail or postfix) or use a different outbound ".
"mail configuration. See this guide for configuring outbound ".
"email:\n");
self::writeDoc('article/Configuring_Outbound_Email.html');
return;
} else {
self::write(" okay Sendmail is configured.\n");
}
break;
case 'PhabricatorMailImplementationAmazonSESAdapter':
$is_ses = true;
$have_adapter = true;
if (PhabricatorEnv::getEnvConfig('metamta.can-send-as-user')) {
self::writeFailure();
self::write(
"Setup failure! 'metamta.can-send-as-user' must be false when ".
"configured with Amazon SES.");
return;
} else {
self::write(" okay Sender config looks okay.\n");
}
if (!PhabricatorEnv::getEnvConfig('amazon-ses.access-key')) {
self::writeFailure();
self::write(
"Setup failure! 'amazon-ses.access-key' is not set, but ".
"outbound mail is configured to deliver via Amazon SES.");
return;
} else {
self::write(" okay Amazon SES access key is set.\n");
}
if (!PhabricatorEnv::getEnvConfig('amazon-ses.secret-key')) {
self::writeFailure();
self::write(
"Setup failure! 'amazon-ses.secret-key' is not set, but ".
"outbound mail is configured to deliver via Amazon SES.");
return;
} else {
self::write(" okay Amazon SES secret key is set.\n");
}
if (PhabricatorEnv::getEnvConfig('metamta.send-immediately')) {
self::writeNote(
"Your configuration uses Amazon SES to deliver email but tries ".
"to send it immediately. This will work, but it's slow. ".
"Consider configuring the MetaMTA daemon.");
}
break;
case 'PhabricatorMailImplementationTestAdapter':
self::write(" skip You have disabled outbound email.\n");
break;
default:
self::write(" skip Configured with a custom adapter.\n");
break;
}
if ($have_adapter) {
$default = PhabricatorEnv::getEnvConfig('metamta.default-address');
if (!$default || $default == 'noreply@example.com') {
self::writeFailure();
self::write(
"Setup failure! You have not set 'metamta.default-address'.");
return;
} else {
self::write(" okay metamta.default-address is set.\n");
}
if ($is_ses) {
self::writeNote(
"Make sure you've verified your 'from' address ('{$default}') with ".
"Amazon SES. Until you verify it, you will be unable to send mail ".
"using Amazon SES.");
}
$domain = PhabricatorEnv::getEnvConfig('metamta.domain');
if (!$domain || $domain == 'example.com') {
self::writeFailure();
self::write(
"Setup failure! You have not set 'metamta.domain'.");
return;
} else {
self::write(" okay metamta.domain is set.\n");
}
self::write("[OKAY] Mail configuration OKAY\n");
}
self::writeHeader('CONFIG CLASSES');
foreach (PhabricatorEnv::getRequiredClasses() as $key => $instanceof) {
$config = PhabricatorEnv::getEnvConfig($key);
if (!$config) {
self::writeNote("'$key' is not set.");
} else {
try {
$r = new ReflectionClass($config);
if (!$r->isSubclassOf($instanceof)) {
throw new Exception(
"Config setting '$key' must be an instance of '$instanceof'.");
} else if (!$r->isInstantiable()) {
throw new Exception("Config setting '$key' must be instantiable.");
}
} catch (Exception $ex) {
self::writeFailure();
self::write("Setup failure! ".$ex->getMessage());
return;
}
}
}
self::write("[OKAY] Config classes OKAY\n");
self::writeHeader('SUCCESS!');
self::write(
"Congratulations! Your setup seems mostly correct, or at least fairly ".
"reasonable.\n\n".
"*** NEXT STEP ***\n".
"Edit your configuration file (conf/{$env}.conf.php) and remove the ".
"'phabricator.setup' line to finish installation.");
}
public static function requireExtension($extension) {
if (extension_loaded($extension)) {
self::write(" okay Extension '{$extension}' installed.\n");
return true;
} else {
self::write("[FAIL] Extension '{$extension}' is NOT INSTALLED!\n");
return false;
}
}
private static function writeFailure() {
self::write("\n\n<<< *** FAILURE! *** >>>\n");
}
private static function write($str) {
echo $str;
ob_flush();
flush();
// This, uh, makes it look cool. -_-
usleep(20000);
}
private static function writeNote($note) {
$note = "*** NOTE: ".wordwrap($note, 75, "\n", true);
$note = "\n".str_replace("\n", "\n ", $note)."\n\n";
self::write($note);
}
public static function writeHeader($header) {
$template = '>>>'.str_repeat('-', 77);
$template = substr_replace(
$template,
' '.$header.' ',
3,
strlen($header) + 4);
self::write("\n\n{$template}\n\n");
}
public static function writeDoc($doc) {
self::write(
"\n".
' http://phabricator.com/docs/phabricator/'.$doc.
"\n\n");
}
}
diff --git a/webroot/index.php b/webroot/index.php
index 866591c892..e9313beeed 100644
--- a/webroot/index.php
+++ b/webroot/index.php
@@ -1,314 +1,316 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
$__start__ = microtime(true);
error_reporting(E_ALL | E_STRICT);
$required_version = '5.2.0';
if (version_compare(PHP_VERSION, $required_version) < 0) {
phabricator_fatal_config_error(
"You are running PHP version '".PHP_VERSION."', which is older than ".
"the minimum version, '{$required_version}'. Update to at least ".
"'{$required_version}'.");
}
phabricator_detect_insane_memory_limit();
ini_set('memory_limit', -1);
$env = getenv('PHABRICATOR_ENV'); // Apache
if (!$env) {
if (isset($_ENV['PHABRICATOR_ENV'])) {
$env = $_ENV['PHABRICATOR_ENV'];
}
}
if (!$env) {
phabricator_fatal_config_error(
"The 'PHABRICATOR_ENV' environmental variable is not defined. Modify ".
"your httpd.conf to include 'SetEnv PHABRICATOR_ENV <env>', where '<env>' ".
"is one of 'development', 'production', or a custom environment.");
}
if (!function_exists('mysql_connect')) {
phabricator_fatal_config_error(
"The PHP MySQL extension is not installed. This extension is required.");
}
if (!isset($_REQUEST['__path__'])) {
phabricator_fatal_config_error(
"__path__ is not set. Your rewrite rules are not configured correctly.");
}
if (get_magic_quotes_gpc()) {
phabricator_fatal_config_error(
"Your server is configured with PHP 'magic_quotes_gpc' enabled. This ".
"feature is 'highly discouraged' by PHP's developers and you must ".
"disable it to run Phabricator. Consult the PHP manual for instructions.");
}
register_shutdown_function('phabricator_shutdown');
require_once dirname(dirname(__FILE__)).'/conf/__init_conf__.php';
try {
setup_aphront_basics();
$conf = phabricator_read_config_file($env);
$conf['phabricator.env'] = $env;
phutil_require_module('phabricator', 'infrastructure/env');
PhabricatorEnv::setEnvConfig($conf);
phutil_require_module('phabricator', 'aphront/console/plugin/xhprof/api');
DarkConsoleXHProfPluginAPI::hookProfiler();
phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
PhutilErrorHandler::initialize();
} catch (Exception $ex) {
phabricator_fatal("[Initialization Exception] ".$ex->getMessage());
}
$tz = PhabricatorEnv::getEnvConfig('phabricator.timezone');
if ($tz) {
date_default_timezone_set($tz);
}
phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
phutil_require_module('phutil', 'error');
PhutilErrorHandler::setErrorListener(
array('DarkConsoleErrorLogPluginAPI', 'handleErrors'));
foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
phutil_load_library($library);
}
if (PhabricatorEnv::getEnvConfig('phabricator.setup')) {
PhabricatorSetup::runSetup();
return;
}
phabricator_detect_bad_base_uri();
$host = $_SERVER['HTTP_HOST'];
$path = $_REQUEST['__path__'];
switch ($host) {
default:
$config_key = 'aphront.default-application-configuration-class';
$application = PhabricatorEnv::newObjectFromConfig($config_key);
break;
}
$application->setHost($host);
$application->setPath($path);
$application->willBuildRequest();
$request = $application->buildRequest();
$write_guard = new AphrontWriteGuard($request);
PhabricatorEventEngine::initialize();
$application->setRequest($request);
list($controller, $uri_data) = $application->buildController();
try {
$response = $controller->willBeginExecution();
if (!$response) {
$controller->willProcessRequest($uri_data);
$response = $controller->processRequest();
}
} catch (AphrontRedirectException $ex) {
$response = id(new AphrontRedirectResponse())
->setURI($ex->getURI());
} catch (Exception $ex) {
$response = $application->handleException($ex);
}
try {
$response = $application->willSendResponse($response);
$response->setRequest($request);
$response_string = $response->buildResponseString();
} catch (Exception $ex) {
$write_guard->dispose();
phabricator_fatal('[Rendering Exception] '.$ex->getMessage());
}
$write_guard->dispose();
// TODO: Share the $sink->writeResponse() pathway here?
$sink = new AphrontPHPHTTPSink();
$sink->writeHTTPStatus($response->getHTTPResponseCode());
$headers = $response->getCacheHeaders();
$headers = array_merge($headers, $response->getHeaders());
$sink->writeHeaders($headers);
// TODO: This shouldn't be possible in a production-configured environment.
if (isset($_REQUEST['__profile__']) &&
($_REQUEST['__profile__'] == 'all')) {
$profile = DarkConsoleXHProfPluginAPI::stopProfiler();
$profile =
'<div style="text-align: center; background: #ff00ff; padding: 1em;
font-size: 24px; font-weight: bold;">'.
'<a href="/xhprof/profile/'.$profile.'/">'.
'>>> View Profile <<<'.
'</a>'.
'</div>';
if (strpos($response_string, '<body>') !== false) {
$response_string = str_replace(
'<body>',
'<body>'.$profile,
$response_string);
} else {
$sink->writeData($profile);
}
}
$sink->writeData($response_string);
/**
* @group aphront
*/
function setup_aphront_basics() {
$aphront_root = dirname(dirname(__FILE__));
$libraries_root = dirname($aphront_root);
$root = null;
if (!empty($_SERVER['PHUTIL_LIBRARY_ROOT'])) {
$root = $_SERVER['PHUTIL_LIBRARY_ROOT'];
}
- ini_set('include_path', $libraries_root.':'.ini_get('include_path'));
+ ini_set(
+ 'include_path',
+ $libraries_root.PATH_SEPARATOR.ini_get('include_path'));
@include_once $root.'libphutil/src/__phutil_library_init__.php';
if (!@constant('__LIBPHUTIL__')) {
echo "ERROR: Unable to load libphutil. Put libphutil/ next to ".
"phabricator/, or update your PHP 'include_path' to include ".
"the parent directory of libphutil/.\n";
exit(1);
}
// Load Phabricator itself using the absolute path, so we never end up doing
// anything surprising (loading index.php and libraries from different
// directories).
phutil_load_library($aphront_root.'/src');
phutil_load_library('arcanist/src');
}
function phabricator_fatal_config_error($msg) {
phabricator_fatal("CONFIG ERROR: ".$msg."\n");
}
function phabricator_detect_bad_base_uri() {
$conf = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
$uri = new PhutilURI($conf);
switch ($uri->getProtocol()) {
case 'http':
case 'https':
break;
default:
return phabricator_fatal_config_error(
"'phabricator.base-uri' is set to '{$conf}', which is invalid. ".
"The URI must start with 'http://' or 'https://'.");
}
if (strpos($uri->getDomain(), '.') === false) {
phabricator_fatal_config_error(
"'phabricator.base-uri' is set to '{$conf}', which is invalid. The URI ".
"must contain a dot ('.'), like 'http://example.com/', not just ".
"'http://example/'. Some web browsers will not set cookies on domains ".
"with no TLD, and Phabricator requires cookies for login. ".
"If you are using localhost, create an entry in the hosts file like ".
"'127.0.0.1 example.com', and access the localhost with ".
"'http://example.com/'.");
}
}
function phabricator_detect_insane_memory_limit() {
$memory_limit = ini_get('memory_limit');
$char_limit = 12;
if (strlen($memory_limit) <= $char_limit) {
return;
}
// colmdoyle ran into an issue on an Ubuntu box with Suhosin where his
// 'memory_limit' was set to:
//
// 3232323232323232323232323232323232323232323232323232323232323232M
//
// Not a typo. A wizard did it.
//
// Anyway, with this 'memory_limit', the machine would immediately fatal
// when executing the ini_set() later. I wasn't able to reproduce this on my
// EC2 Ubuntu + Suhosin box, but verified that it caused the problem on his
// machine and that setting it to a more sensible value fixed it. Since I
// have no idea how to actually trigger the issue, we look for a coarse
// approximation of it (a memory_limit setting more than 12 characters in
// length).
phabricator_fatal_config_error(
"Your PHP 'memory_limit' is set to something ridiculous ".
"(\"{$memory_limit}\"). Set it to a more reasonable value (it must be no ".
"more than {$char_limit} characters long).");
}
function phabricator_shutdown() {
$event = error_get_last();
if (!$event) {
return;
}
if ($event['type'] != E_ERROR && $event['type'] != E_PARSE) {
return;
}
$msg = ">>> UNRECOVERABLE FATAL ERROR <<<\n\n";
if ($event) {
// Even though we should be emitting this as text-plain, escape things just
// to be sure since we can't really be sure what the program state is when
// we get here.
$msg .= phutil_escape_html($event['message'])."\n\n";
$msg .= phutil_escape_html($event['file'].':'.$event['line']);
}
// flip dem tables
$msg .= "\n\n\n";
$msg .= "\xe2\x94\xbb\xe2\x94\x81\xe2\x94\xbb\x20\xef\xb8\xb5\x20\xc2\xaf".
"\x5c\x5f\x28\xe3\x83\x84\x29\x5f\x2f\xc2\xaf\x20\xef\xb8\xb5\x20".
"\xe2\x94\xbb\xe2\x94\x81\xe2\x94\xbb";
phabricator_fatal($msg);
}
function phabricator_fatal($msg) {
header(
'Content-Type: text/plain; charset=utf-8',
$replace = true,
$http_error = 500);
error_log($msg);
echo $msg;
exit(1);
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 19:37 (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128046
Default Alt Text
(44 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment