protected function init() { parent::init(); if (!Director::is_cli() && !Permission::check('ADMIN')) { Security::permissionFailure(); } }
protected function init() { parent::init(); // Unless called from the command line, all CliControllers need ADMIN privileges if (!Director::is_cli() && !Permission::check("ADMIN")) { Security::permissionFailure(); } }
/** * Require basic authentication. Will request a username and password if none is given. * * Used by {@link Controller::init()}. * * @throws HTTPResponse_Exception * * @param string $realm * @param string|array $permissionCode Optional * @param boolean $tryUsingSessionLogin If true, then the method with authenticate against the * session log-in if those credentials are disabled. * @return Member|bool $member */ public static function requireLogin($realm, $permissionCode = null, $tryUsingSessionLogin = true) { $isRunningTests = class_exists('SilverStripe\\Dev\\SapphireTest', false) && SapphireTest::is_running_test(); if (!Security::database_is_ready() || Director::is_cli() && !$isRunningTests) { return true; } /* * Enable HTTP Basic authentication workaround for PHP running in CGI mode with Apache * Depending on server configuration the auth header may be in HTTP_AUTHORIZATION or * REDIRECT_HTTP_AUTHORIZATION * * The follow rewrite rule must be in the sites .htaccess file to enable this workaround * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] */ $authHeader = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) ? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] : null); $matches = array(); if ($authHeader && preg_match('/Basic\\s+(.*)$/i', $authHeader, $matches)) { list($name, $password) = explode(':', base64_decode($matches[1])); $_SERVER['PHP_AUTH_USER'] = strip_tags($name); $_SERVER['PHP_AUTH_PW'] = strip_tags($password); } $member = null; if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { $member = MemberAuthenticator::authenticate(array('Email' => $_SERVER['PHP_AUTH_USER'], 'Password' => $_SERVER['PHP_AUTH_PW']), null); } if (!$member && $tryUsingSessionLogin) { $member = Member::currentUser(); } // If we've failed the authentication mechanism, then show the login form if (!$member) { $response = new HTTPResponse(null, 401); $response->addHeader('WWW-Authenticate', "Basic realm=\"{$realm}\""); if (isset($_SERVER['PHP_AUTH_USER'])) { $response->setBody(_t('BasicAuth.ERRORNOTREC', "That username / password isn't recognised")); } else { $response->setBody(_t('BasicAuth.ENTERINFO', "Please enter a username and password.")); } // Exception is caught by RequestHandler->handleRequest() and will halt further execution $e = new HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } if ($permissionCode && !Permission::checkMember($member->ID, $permissionCode)) { $response = new HTTPResponse(null, 401); $response->addHeader('WWW-Authenticate', "Basic realm=\"{$realm}\""); if (isset($_SERVER['PHP_AUTH_USER'])) { $response->setBody(_t('BasicAuth.ERRORNOTADMIN', "That user is not an administrator.")); } // Exception is caught by RequestHandler->handleRequest() and will halt further execution $e = new HTTPResponse_Exception(null, 401); $e->setResponse($response); throw $e; } return $member; }
/** * Render or return a backtrace from the given scope. * * @param mixed $returnVal * @param bool $ignoreAjax * @param array $ignoredFunctions * @return mixed */ public static function backtrace($returnVal = false, $ignoreAjax = false, $ignoredFunctions = null) { $plainText = Director::is_cli() || Director::is_ajax() && !$ignoreAjax; $result = self::get_rendered_backtrace(debug_backtrace(), $plainText, $ignoredFunctions); if ($returnVal) { return $result; } else { echo $result; return null; } }
public function run($request) { if (!Permission::check('ADMIN') && !Director::is_cli()) { $response = Security::permissionFailure(); if ($response) { $response->output(); } die; } SapphireTest::delete_all_temp_dbs(); }
public function index() { if (!Director::is_cli()) { return "The SilverStripe Interactive Command-line doesn't work in a web browser." . " Use 'sake interactive' from the command-line to run."; } /* Try using PHP_Shell if it exists */ @(include 'php-shell-cmd.php'); /* Fall back to our simpler interface */ if (empty($__shell)) { set_error_handler(array($this, 'error_handler')); echo "SilverStripe Interactive Command-line (REPL interface). Type help for hints.\n\n"; while (true) { echo CLI::text("?> ", "cyan"); echo CLI::start_colour("yellow"); $command = trim(fgets(STDIN, 4096)); echo CLI::end_colour(); if ($command == 'help' || $command == '?') { print "help or ? to exit\n"; print "quit or \\q to exit\n"; print "install PHP_Shell for a more advanced interface with" . " auto-completion and readline support\n\n"; continue; } if ($command == 'quit' || $command == '\\q') { break; } // Simple command processing if (substr($command, -1) == ';') { $command = substr($command, 0, -1); } $is_print = preg_match('/^\\s*print/i', $command); $is_return = preg_match('/^\\s*return/i', $command); if (!$is_print && !$is_return) { $command = "return ({$command})"; } $command .= ";"; try { $result = eval($command); if (!$is_print) { print_r($result); } echo "\n"; } catch (Exception $__repl_exception) { echo CLI::start_colour("red"); printf('%s (code: %d) got thrown' . PHP_EOL, get_class($__repl_exception), $__repl_exception->getCode()); print $__repl_exception; echo "\n"; } } } }
public function build($request) { if (Director::is_cli()) { $da = DatabaseAdmin::create(); return $da->handleRequest($request, $this->model); } else { $renderer = DebugView::create(); echo $renderer->renderHeader(); echo $renderer->renderInfo("Environment Builder", Director::absoluteBaseURL()); echo "<div class=\"build\">"; $da = DatabaseAdmin::create(); $response = $da->handleRequest($request, $this->model); echo "</div>"; echo $renderer->renderFooter(); return $response; } }
protected function getAndCheckForError($url) { $this->logInWithPermission('ADMIN'); if (Director::is_cli()) { // when in CLI the admin controller throws exceptions ob_start(); try { $this->get($url); } catch (Exception $e) { ob_end_clean(); return true; } ob_end_clean(); return false; } else { // when in http the admin controller sets a response header ob_start(); $resp = $this->get($url); ob_end_clean(); return $resp->isError(); } }
/** * Updates the database schema, creating tables & fields as necessary. * * @param boolean $quiet Don't show messages * @param boolean $populate Populate the database, as well as setting up its schema * @param bool $testMode */ public function doBuild($quiet = false, $populate = true, $testMode = false) { if ($quiet) { DB::quiet(); } else { $conn = DB::get_conn(); // Assumes database class is like "MySQLDatabase" or "MSSQLDatabase" (suffixed with "Database") $dbType = substr(get_class($conn), 0, -8); $dbVersion = $conn->getVersion(); $databaseName = method_exists($conn, 'currentDatabase') ? $conn->getSelectedDatabase() : ""; if (Director::is_cli()) { echo sprintf("\n\nBuilding database %s using %s %s\n\n", $databaseName, $dbType, $dbVersion); } else { echo sprintf("<h2>Building database %s using %s %s</h2>", $databaseName, $dbType, $dbVersion); } } // Set up the initial database if (!DB::is_active()) { if (!$quiet) { echo '<p><b>Creating database</b></p>'; } // Load parameters from existing configuration global $databaseConfig; if (empty($databaseConfig) && empty($_REQUEST['db'])) { user_error("No database configuration available", E_USER_ERROR); } $parameters = !empty($databaseConfig) ? $databaseConfig : $_REQUEST['db']; // Check database name is given if (empty($parameters['database'])) { user_error("No database name given; please give a value for \$databaseConfig['database']", E_USER_ERROR); } $database = $parameters['database']; // Establish connection and create database in two steps unset($parameters['database']); DB::connect($parameters); DB::create_database($database); } // Build the database. Most of the hard work is handled by DataObject $dataClasses = ClassInfo::subclassesFor('SilverStripe\\ORM\\DataObject'); array_shift($dataClasses); if (!$quiet) { if (Director::is_cli()) { echo "\nCREATING DATABASE TABLES\n\n"; } else { echo "\n<p><b>Creating database tables</b></p>\n\n"; } } // Initiate schema update $dbSchema = DB::get_schema(); $dbSchema->schemaUpdate(function () use($dataClasses, $testMode, $quiet) { foreach ($dataClasses as $dataClass) { // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness if (!class_exists($dataClass)) { continue; } // Check if this class should be excluded as per testing conventions $SNG = singleton($dataClass); if (!$testMode && $SNG instanceof TestOnly) { continue; } // Log data if (!$quiet) { if (Director::is_cli()) { echo " * {$dataClass}\n"; } else { echo "<li>{$dataClass}</li>\n"; } } // Instruct the class to apply its schema to the database $SNG->requireTable(); } }); ClassInfo::reset_db_cache(); if ($populate) { if (!$quiet) { if (Director::is_cli()) { echo "\nCREATING DATABASE RECORDS\n\n"; } else { echo "\n<p><b>Creating database records</b></p>\n\n"; } } foreach ($dataClasses as $dataClass) { // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness // Test_ indicates that it's the data class is part of testing system if (strpos($dataClass, 'Test_') === false && class_exists($dataClass)) { if (!$quiet) { if (Director::is_cli()) { echo " * {$dataClass}\n"; } else { echo "<li>{$dataClass}</li>\n"; } } singleton($dataClass)->requireDefaultRecords(); } } // Remap obsolete class names $schema = DataObject::getSchema(); foreach ($this->config()->classname_value_remapping as $oldClassName => $newClassName) { $baseDataClass = $schema->baseDataClass($newClassName); $badRecordCount = DataObject::get($baseDataClass)->filter(["ClassName" => $oldClassName])->count(); if ($badRecordCount > 0) { if (Director::is_cli()) { echo " * Correcting {$badRecordCount} obsolete classname values for {$newClassName}\n"; } else { echo "<li>Correcting {$badRecordCount} obsolete classname values for {$newClassName}</li>\n"; } $table = $schema->baseDataTable($baseDataClass); DB::prepared_query("UPDATE \"{$table}\" SET \"ClassName\" = ? WHERE \"ClassName\" = ?", [$newClassName, $oldClassName]); } } } touch(TEMP_FOLDER . '/database-last-generated-' . str_replace(array('\\', '/', ':'), '.', Director::baseFolder())); if (isset($_REQUEST['from_installer'])) { echo "OK"; } if (!$quiet) { echo Director::is_cli() ? "\n Database build completed!\n\n" : "<p>Database build completed!</p>"; } ClassInfo::reset_db_cache(); }
public static function delete_all_temp_dbs() { $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; foreach (DB::get_schema()->databaseList() as $dbName) { if (preg_match(sprintf('/^%stmpdb[0-9]+$/', $prefix), $dbName)) { DB::get_schema()->dropDatabase($dbName); if (Director::is_cli()) { echo "Dropped database \"{$dbName}\"" . PHP_EOL; } else { echo "<li>Dropped database \"{$dbName}\"</li>" . PHP_EOL; } flush(); } } }
/** * Create an instance of an appropriate DebugView object. * * @return DebugView */ public static function create_debug_view() { $service = Director::is_cli() || Director::is_ajax() ? 'SilverStripe\\Dev\\CliDebugView' : 'SilverStripe\\Dev\\DebugView'; return Injector::inst()->get($service); }
/** * Returns the domain part of the URL 'http://www.mysite.com'. Returns FALSE is this environment * variable isn't set. * * @return bool|string */ public static function protocolAndHost() { $alternate = Config::inst()->get('SilverStripe\\Control\\Director', 'alternate_base_url'); if ($alternate) { if (preg_match('/^(http[^:]*:\\/\\/[^\\/]+)(\\/|$)/', $alternate, $matches)) { return $matches[1]; } } if (isset($_SERVER['HTTP_HOST'])) { return Director::protocol() . $_SERVER['HTTP_HOST']; } else { global $_FILE_TO_URL_MAPPING; if (Director::is_cli() && isset($_FILE_TO_URL_MAPPING)) { $errorSuggestion = ' You probably want to define ' . 'an entry in $_FILE_TO_URL_MAPPING that covers "' . Director::baseFolder() . '"'; } elseif (Director::is_cli()) { $errorSuggestion = ' You probably want to define $_FILE_TO_URL_MAPPING in ' . 'your _ss_environment.php as instructed on the "sake" page of the doc.silverstripe.com wiki'; } else { $errorSuggestion = ""; } user_error("Director::protocolAndHost() lacks sufficient information - HTTP_HOST not set." . $errorSuggestion, E_USER_WARNING); return false; } }
/** * Show a message about database alteration * * @param string $message to display * @param string $type one of [created|changed|repaired|obsolete|deleted|error] */ public function alterationMessage($message, $type = "") { if (!$this->supressOutput) { if (Director::is_cli()) { switch ($type) { case "created": case "changed": case "repaired": $sign = "+"; break; case "obsolete": case "deleted": $sign = '-'; break; case "notice": $sign = '*'; break; case "error": $sign = "!"; break; default: $sign = " "; } $message = strip_tags($message); echo " {$sign} {$message}\n"; } else { switch ($type) { case "created": $color = "green"; break; case "obsolete": $color = "red"; break; case "notice": $color = "orange"; break; case "error": $color = "red"; break; case "deleted": $color = "red"; break; case "changed": $color = "blue"; break; case "repaired": $color = "blue"; break; default: $color = ""; } echo "<li style=\"color: {$color}\">{$message}</li>"; } } }
/** * Regenerate the session_id. * This wrapper is here to make it easier to disable calls to session_regenerate_id(), should you need to. * They have caused problems in certain * quirky problems (such as using the Windmill 0.3.6 proxy). */ public static function session_regenerate_id() { if (!self::config()->session_regenerate_id) { return; } // This can be called via CLI during testing. if (Director::is_cli()) { return; } $file = ''; $line = ''; // @ is to supress win32 warnings/notices when session wasn't cleaned up properly // There's nothing we can do about this, because it's an operating system function! if (!headers_sent($file, $line)) { @session_regenerate_id(true); } }
/** * Choose the stage the site is currently on. * * If $_GET['stage'] is set, then it will use that stage, and store it in * the session. * * if $_GET['archiveDate'] is set, it will use that date, and store it in * the session. * * If neither of these are set, it checks the session, otherwise the stage * is set to 'Live'. */ public static function choose_site_stage() { // Check any pre-existing session mode $preexistingMode = Session::get('readingMode'); // Determine the reading mode if (isset($_GET['stage'])) { $stage = ucfirst(strtolower($_GET['stage'])); if (!in_array($stage, array(static::DRAFT, static::LIVE))) { $stage = static::LIVE; } $mode = 'Stage.' . $stage; } elseif (isset($_GET['archiveDate']) && strtotime($_GET['archiveDate'])) { $mode = 'Archive.' . $_GET['archiveDate']; } elseif ($preexistingMode) { $mode = $preexistingMode; } else { $mode = static::DEFAULT_MODE; } // Save reading mode Versioned::set_reading_mode($mode); // Try not to store the mode in the session if not needed if ($preexistingMode && $preexistingMode !== $mode || !$preexistingMode && $mode !== static::DEFAULT_MODE) { Session::set('readingMode', $mode); } if (!headers_sent() && !Director::is_cli()) { if (Versioned::get_stage() == 'Live') { // clear the cookie if it's set if (Cookie::get('bypassStaticCache')) { Cookie::force_expiry('bypassStaticCache', null, null, false, true); } } else { // set the cookie if it's cleared if (!Cookie::get('bypassStaticCache')) { Cookie::set('bypassStaticCache', '1', 0, null, null, false, true); } } } }
/** * @return array Array of associative arrays for each task (Keys: 'class', 'title', 'description') */ protected function getTasks() { $availableTasks = array(); $taskClasses = ClassInfo::subclassesFor('SilverStripe\\Dev\\BuildTask'); // remove the base class array_shift($taskClasses); foreach ($taskClasses as $class) { if (!$this->taskEnabled($class)) { continue; } $singleton = BuildTask::singleton($class); $desc = Director::is_cli() ? Convert::html2raw($singleton->getDescription()) : $singleton->getDescription(); $availableTasks[] = array('class' => $class, 'title' => $singleton->getTitle(), 'segment' => $singleton->config()->segment ?: str_replace('\\', '-', $class), 'description' => $desc); } return $availableTasks; }
/** * Build the default data, calling requireDefaultRecords on all * DataObject classes * Should match the $url_handlers rule: * 'build/defaults' => 'buildDefaults', */ public function buildDefaults() { $da = DatabaseAdmin::create(); $renderer = null; if (!Director::is_cli()) { $renderer = DebugView::create(); echo $renderer->renderHeader(); echo $renderer->renderInfo("Defaults Builder", Director::absoluteBaseURL()); echo "<div style=\"margin: 0 2em\">"; } $da->buildDefaults(); if (!Director::is_cli()) { echo "</div>"; echo $renderer->renderFooter(); } }
/** * Set an alternative database in a browser cookie, * with the cookie lifetime set to the browser session. * This is useful for integration testing on temporary databases. * * There is a strict naming convention for temporary databases to avoid abuse: * <prefix> (default: 'ss_') + tmpdb + <7 digits> * As an additional security measure, temporary databases will * be ignored in "live" mode. * * Note that the database will be set on the next request. * Set it to null to revert to the main database. * @param string $name */ public static function set_alternative_database_name($name = null) { // Skip if CLI if (Director::is_cli()) { return; } if ($name) { if (!self::valid_alternative_database_name($name)) { throw new InvalidArgumentException(sprintf('Invalid alternative database name: "%s"', $name)); } $key = Config::inst()->get('SilverStripe\\Security\\Security', 'token'); if (!$key) { throw new LogicException('"Security.token" not found, run "sake dev/generatesecuretoken"'); } if (!function_exists('mcrypt_encrypt')) { throw new LogicException('DB::set_alternative_database_name() requires the mcrypt PHP extension'); } $key = md5($key); // Ensure key is correct length for chosen cypher $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB); $iv = mcrypt_create_iv($ivSize); $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $name, MCRYPT_MODE_CFB, $iv); // Set to browser session lifetime, and restricted to HTTP access only Cookie::set("alternativeDatabaseName", base64_encode($encrypted), 0, null, null, false, true); Cookie::set("alternativeDatabaseNameIv", base64_encode($iv), 0, null, null, false, true); } else { Cookie::force_expiry("alternativeDatabaseName", null, null, false, true); Cookie::force_expiry("alternativeDatabaseNameIv", null, null, false, true); } }