/**
  * @param array $record
  * @return bool
  */
 protected function write(array $record)
 {
     ini_set('display_errors', 0);
     // TODO: This coupling isn't ideal
     // See https://github.com/silverstripe/silverstripe-framework/issues/4484
     if (Controller::has_curr()) {
         $response = Controller::curr()->getResponse();
     } else {
         $response = new HTTPResponse();
     }
     // If headers have been sent then these won't be used, and may throw errors that we wont' want to see.
     if (!headers_sent()) {
         $response->setStatusCode($this->statusCode);
         $response->addHeader("Content-Type", $this->contentType);
     } else {
         // To supress errors aboot errors
         $response->setStatusCode(200);
     }
     $response->setBody($record['formatted']);
     $response->output();
     return false === $this->bubble;
 }
 /**
  * Create a response with the given error code
  *
  * @param int $code
  * @return HTTPResponse
  */
 protected function createErrorResponse($code)
 {
     $response = new HTTPResponse('', $code);
     // Show message in dev
     if (!Director::isLive()) {
         $response->setBody($response->getStatusDescription());
     }
     return $response;
 }
 /**
  * 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;
 }
 /**
  * Process the given URL, creating the appropriate controller and executing it.
  *
  * Request processing is handled as follows:
  * - Director::direct() creates a new HTTPResponse object and passes this to
  *   Director::handleRequest().
  * - Director::handleRequest($request) checks each of the Director rules and identifies a controller
  *   to handle this request.
  * - Controller::handleRequest($request) is then called.  This will find a rule to handle the URL,
  *   and call the rule handling method.
  * - RequestHandler::handleRequest($request) is recursively called whenever a rule handling method
  *   returns a RequestHandler object.
  *
  * In addition to request processing, Director will manage the session, and perform the output of
  * the actual response to the browser.
  *
  * @uses handleRequest() rule-lookup logic is handled by this.
  * @uses Controller::handleRequest() This handles the page logic for a Director::direct() call.
  * @param string $url
  * @param DataModel $model
  * @throws HTTPResponse_Exception
  */
 public static function direct($url, DataModel $model)
 {
     // Validate $_FILES array before merging it with $_POST
     foreach ($_FILES as $k => $v) {
         if (is_array($v['tmp_name'])) {
             $v = ArrayLib::array_values_recursive($v['tmp_name']);
             foreach ($v as $tmpFile) {
                 if ($tmpFile && !is_uploaded_file($tmpFile)) {
                     user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR);
                 }
             }
         } else {
             if ($v['tmp_name'] && !is_uploaded_file($v['tmp_name'])) {
                 user_error("File upload '{$k}' doesn't appear to be a valid upload", E_USER_ERROR);
             }
         }
     }
     $req = new HTTPRequest(isset($_SERVER['X-HTTP-Method-Override']) ? $_SERVER['X-HTTP-Method-Override'] : $_SERVER['REQUEST_METHOD'], $url, $_GET, ArrayLib::array_merge_recursive((array) $_POST, (array) $_FILES), @file_get_contents('php://input'));
     $headers = self::extract_request_headers($_SERVER);
     foreach ($headers as $header => $value) {
         $req->addHeader($header, $value);
     }
     // Initiate an empty session - doesn't initialize an actual PHP session until saved (see below)
     $session = Session::create(isset($_SESSION) ? $_SESSION : array());
     // Only resume a session if its not started already, and a session identifier exists
     if (!isset($_SESSION) && Session::request_contains_session_id()) {
         $session->inst_start();
     }
     $output = RequestProcessor::singleton()->preRequest($req, $session, $model);
     if ($output === false) {
         // @TODO Need to NOT proceed with the request in an elegant manner
         throw new HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400);
     }
     $result = Director::handleRequest($req, $session, $model);
     // Save session data. Note that inst_save() will start/resume the session if required.
     $session->inst_save();
     // Return code for a redirection request
     if (is_string($result) && substr($result, 0, 9) == 'redirect:') {
         $url = substr($result, 9);
         if (Director::is_cli()) {
             // on cli, follow SilverStripe redirects automatically
             Director::direct(str_replace(Director::absoluteBaseURL(), '', $url), DataModel::inst());
             return;
         } else {
             $response = new HTTPResponse();
             $response->redirect($url);
             $res = RequestProcessor::singleton()->postRequest($req, $response, $model);
             if ($res !== false) {
                 $response->output();
             }
         }
         // Handle a controller
     } elseif ($result) {
         if ($result instanceof HTTPResponse) {
             $response = $result;
         } else {
             $response = new HTTPResponse();
             $response->setBody($result);
         }
         $res = RequestProcessor::singleton()->postRequest($req, $response, $model);
         if ($res !== false) {
             $response->output();
         } else {
             // @TODO Proper response here.
             throw new HTTPResponse_Exception("Invalid response");
         }
         //$controllerObj->getSession()->inst_save();
     }
 }
 /**
  * REST endpoint to get a list of campaigns.
  *
  * @return HTTPResponse
  */
 public function readCampaigns()
 {
     $response = new HTTPResponse();
     $response->addHeader('Content-Type', 'application/json');
     $hal = $this->getListResource();
     $response->setBody(Convert::array2json($hal));
     return $response;
 }
 /**
  * Performs the following replacements:
  * - Check user defined content type and use it, if it's empty use the text/html.
  * - If find a XML header replaces it and existing doctypes with HTML4.01 Strict.
  * - Replaces self-closing tags like <img /> with unclosed solitary tags like <img>.
  * - Replaces all occurrences of "application/xhtml+xml" with "text/html" in the template.
  * - Removes "xmlns" attributes and any <?xml> Pragmas.
  *
  * @param HTTPResponse $response
  */
 public function html(HTTPResponse $response)
 {
     $encoding = $this->config()->get('encoding');
     $contentType = $this->config()->get('content_type');
     if (empty($contentType)) {
         $response->addHeader("Content-Type", "text/html; charset=" . $encoding);
     } else {
         $response->addHeader("Content-Type", $contentType . "; charset=" . $encoding);
     }
     $response->addHeader("Vary", "Accept");
     $content = $response->getBody();
     $hasXMLHeader = substr($content, 0, 5) == '<' . '?xml';
     // Fix base tag
     $content = preg_replace('/<base href="([^"]*)" \\/>/', '<base href="$1"><!--[if lte IE 6]></base><![endif]-->', $content);
     $content = preg_replace("#<\\?xml[^>]+\\?>\n?#", '', $content);
     $content = str_replace(array('/>', 'xml:lang', 'application/xhtml+xml'), array('>', 'lang', 'text/html'), $content);
     // Only replace the doctype in templates with the xml header
     if ($hasXMLHeader) {
         $content = preg_replace('/<!DOCTYPE[^>]+>/', '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">', $content);
     }
     $content = preg_replace('/<html xmlns="[^"]+"/', '<html ', $content);
     $response->setBody($content);
 }
 /**
  * @param HTTPRequest $request
  *
  * @return HTTPResponse
  */
 public function apiSearch(HTTPRequest $request)
 {
     $params = $request->getVars();
     $list = $this->getList($params);
     $response = new HTTPResponse();
     $response->addHeader('Content-Type', 'application/json');
     $response->setBody(json_encode(["files" => array_map(function ($file) {
         return $this->getObjectFromData($file);
     }, $list->toArray()), "count" => $list->count()]));
     return $response;
 }