Browse Source

more refactoring for 2.0

Taylor Otwell 12 years ago
parent
commit
a8dbe777df

+ 1 - 0
application/config/aliases.php

@@ -39,6 +39,7 @@ return array(
 	'IoC'        => 'Laravel\\IoC',
 	'Lang'       => 'Laravel\\Facades\\Lang',
 	'Loader'     => 'Laravel\\Facades\\Loader',
+	'Messages'   => 'Laravel\\Validation\\Messages',
 	'Package'    => 'Laravel\\Facades\\Package',
 	'URL'        => 'Laravel\\Facades\\URL',
 	'Redirect'   => 'Laravel\\Facades\\Redirect',

+ 1 - 1
application/filters.php

@@ -62,7 +62,7 @@ return array(
 
 	'csrf' => function()
 	{
-		return (Input::get('csrf_token') !== Form::raw_token()) ? new Error('500') : null;
+		return (Input::get('csrf_token') !== Form::raw_token()) ? Response::error('500') : null;
 	},
 
 );

+ 25 - 0
laravel/arr.php

@@ -110,4 +110,29 @@ class Arr {
 		return ($default instanceof \Closure) ? call_user_func($default) : $default;
 	}
 
+	/**
+	 * Remove all values in the array that are contained within a given array of values.
+	 *
+	 * <code>
+	 *		// Remove all empty string values from an array
+	 *		$array = Arr::without($array, array(''));
+	 *
+	 *		// Remove all array values that are "3", "2", or "1"
+	 *		$array = Arr::without($array, array(3, 2, 1));
+	 * </code>
+	 *
+	 * @param  array  $array
+	 * @param  array  $without
+	 * @return array
+	 */
+	public static function without($array, $without = array())
+	{
+		foreach ($array as $key => $value)
+		{
+			if (in_array($value, $without)) unset($array[$key]);
+		}
+
+		return $array;
+	}
+
 }

+ 9 - 3
laravel/config/container.php

@@ -79,7 +79,7 @@ return array(
 
 	'laravel.hasher' => array('singleton' => true, 'resolver' => function($container)
 	{
-		return new Security\Hashing\Bcrypt(8);
+		return new Security\Hashing\Bcrypt(8, false);
 	}),
 
 
@@ -158,9 +158,15 @@ return array(
 	}),
 
 
-	'laravel.routing.router' => array('singleton' => true, 'resolver' => function($container)
+	'laravel.routing.router' => array('singleton' => true, 'resolver' => function($c)
 	{
-		return new Routing\Router(require APP_PATH.'routes'.EXT, CONTROLLER_PATH);
+		return new Routing\Router($c->resolve('laravel.routing.loader'), CONTROLLER_PATH);
+	}),
+
+
+	'laravel.routing.loader' => array('singleton' => true, 'resolver' => function($container)
+	{
+		return new Routing\Loader(APP_PATH, ROUTE_PATH);
 	}),
 
 

+ 71 - 70
laravel/bootstrap.php → laravel/core.php

@@ -1,71 +1,72 @@
-<?php namespace Laravel;
-
-// --------------------------------------------------------------
-// Define the PHP file extension.
-// --------------------------------------------------------------
-define('EXT', '.php');
-
-// --------------------------------------------------------------
-// Define the core framework paths.
-// --------------------------------------------------------------
-define('APP_PATH',     realpath($application).'/');
-define('BASE_PATH',    realpath(str_replace('laravel', '', $laravel)).'/');
-define('PACKAGE_PATH', realpath($packages).'/');
-define('PUBLIC_PATH',  realpath($public).'/');
-define('STORAGE_PATH', realpath($storage).'/');
-define('SYS_PATH',     realpath($laravel).'/');
-
-unset($laravel, $application, $config, $packages, $public, $storage);
-
-// --------------------------------------------------------------
-// Define various other framework paths.
-// --------------------------------------------------------------
-define('CACHE_PATH',      STORAGE_PATH.'cache/');
-define('CONFIG_PATH',     APP_PATH.'config/');
-define('CONTROLLER_PATH', APP_PATH.'controllers/');
-define('DATABASE_PATH',   STORAGE_PATH.'database/');
-define('LANG_PATH',       APP_PATH.'language/');
-define('SESSION_PATH',    STORAGE_PATH.'sessions/');
-define('SYS_CONFIG_PATH', SYS_PATH.'config/');
-define('SYS_LANG_PATH',   SYS_PATH.'language/');
-define('VIEW_PATH',       APP_PATH.'views/');
-
-// --------------------------------------------------------------
-// Load the configuration manager and its dependencies.
-// --------------------------------------------------------------
-require SYS_PATH.'facades'.EXT;
-require SYS_PATH.'config'.EXT;
-require SYS_PATH.'arr'.EXT;
-
-// --------------------------------------------------------------
-// Bootstrap the IoC container.
-// --------------------------------------------------------------
-require SYS_PATH.'container'.EXT;
-
-$dependencies = require SYS_CONFIG_PATH.'container'.EXT;
-
-if (file_exists($path = CONFIG_PATH.'container'.EXT))
-{
-	$dependencies = array_merge($dependencies, require $path);
-}
-
-$env = (isset($_SERVER['LARAVEL_ENV'])) ? $_SERVER['LARAVEL_ENV'] : null;
-
-if ( ! is_null($env) and file_exists($path = CONFIG_PATH.$env.'/container'.EXT))
-{
-	$dependencies = array_merge($dependencies, require $path);
-}
-
-$container = new Container($dependencies);
-
-IoC::$container = $container;
-
-// --------------------------------------------------------------
-// Register the auto-loader on the auto-loader stack.
-// --------------------------------------------------------------
-spl_autoload_register(array($container->resolve('laravel.loader'), 'load'));
-
-// --------------------------------------------------------------
-// Set the application environment configuration option.
-// --------------------------------------------------------------
+<?php namespace Laravel;
+
+// --------------------------------------------------------------
+// Define the PHP file extension.
+// --------------------------------------------------------------
+define('EXT', '.php');
+
+// --------------------------------------------------------------
+// Define the core framework paths.
+// --------------------------------------------------------------
+define('APP_PATH',     realpath($application).'/');
+define('BASE_PATH',    realpath(str_replace('laravel', '', $laravel)).'/');
+define('PACKAGE_PATH', realpath($packages).'/');
+define('PUBLIC_PATH',  realpath($public).'/');
+define('STORAGE_PATH', realpath($storage).'/');
+define('SYS_PATH',     realpath($laravel).'/');
+
+unset($laravel, $application, $config, $packages, $public, $storage);
+
+// --------------------------------------------------------------
+// Define various other framework paths.
+// --------------------------------------------------------------
+define('CACHE_PATH',      STORAGE_PATH.'cache/');
+define('CONFIG_PATH',     APP_PATH.'config/');
+define('CONTROLLER_PATH', APP_PATH.'controllers/');
+define('DATABASE_PATH',   STORAGE_PATH.'database/');
+define('LANG_PATH',       APP_PATH.'language/');
+define('ROUTE_PATH',      APP_PATH.'routes/');
+define('SESSION_PATH',    STORAGE_PATH.'sessions/');
+define('SYS_CONFIG_PATH', SYS_PATH.'config/');
+define('SYS_LANG_PATH',   SYS_PATH.'language/');
+define('VIEW_PATH',       APP_PATH.'views/');
+
+// --------------------------------------------------------------
+// Load the configuration manager and its dependencies.
+// --------------------------------------------------------------
+require SYS_PATH.'facades'.EXT;
+require SYS_PATH.'config'.EXT;
+require SYS_PATH.'arr'.EXT;
+
+// --------------------------------------------------------------
+// Bootstrap the IoC container.
+// --------------------------------------------------------------
+require SYS_PATH.'container'.EXT;
+
+$dependencies = require SYS_CONFIG_PATH.'container'.EXT;
+
+if (file_exists($path = CONFIG_PATH.'container'.EXT))
+{
+	$dependencies = array_merge($dependencies, require $path);
+}
+
+$env = (isset($_SERVER['LARAVEL_ENV'])) ? $_SERVER['LARAVEL_ENV'] : null;
+
+if ( ! is_null($env) and file_exists($path = CONFIG_PATH.$env.'/container'.EXT))
+{
+	$dependencies = array_merge($dependencies, require $path);
+}
+
+$container = new Container($dependencies);
+
+IoC::$container = $container;
+
+// --------------------------------------------------------------
+// Register the auto-loader on the auto-loader stack.
+// --------------------------------------------------------------
+spl_autoload_register(array($container->resolve('laravel.loader'), 'load'));
+
+// --------------------------------------------------------------
+// Set the application environment configuration option.
+// --------------------------------------------------------------
 $container->resolve('laravel.config')->set('application.env', $env);

+ 1 - 1
laravel/laravel.php

@@ -3,7 +3,7 @@
 // --------------------------------------------------------------
 // Bootstrap the core framework components.
 // --------------------------------------------------------------
-require 'bootstrap.php';
+require 'core.php';
 
 // --------------------------------------------------------------
 // Get an instance of the configuration manager.

+ 31 - 4
laravel/routing/caller.php

@@ -4,6 +4,28 @@ use Closure;
 use Laravel\Response;
 use Laravel\Container;
 
+class Delegate {
+
+	/**
+	 * The destination of the route delegate.
+	 *
+	 * @var string
+	 */
+	public $destination;
+
+	/**
+	 * Create a new route delegate instance.
+	 *
+	 * @param  string  $destination
+	 * @return void
+	 */
+	public function __construct($destination)
+	{
+		$this->destination = $destination;
+	}
+
+}
+
 class Caller {
 
 	/**
@@ -60,10 +82,10 @@ class Caller {
 
 		if ( ! is_null($response = $route->call()))
 		{
-			// If a route returns a string, it also means the route is delegating the
-			// handling of the request to a controller method. So, we will pass the
-			// string to the route delegator, exploding on "@".
-			if (is_string($response)) $response = $this->delegate($route, $response);
+			// If a route returns a Delegate, it also means the route is delegating the
+			// handling of the request to a controller method. So, we will pass the string
+			// to the route delegator, exploding on "@".
+			if ($response instanceof Delegate) $response = $this->delegate($route, $response->destination);
 
 			return $this->finish($route, $response);
 		}
@@ -98,6 +120,11 @@ class Caller {
 	 */
 	protected function delegate(Route $route, $delegate)
 	{
+		if (strpos($delegate, '@') === false)
+		{
+			throw new \Exception("Route delegate [$delegate] has an invalid format.");
+		}
+
 		list($controller, $method) = explode('@', $delegate);
 
 		$controller = $this->resolve($controller);

+ 107 - 0
laravel/routing/loader.php

@@ -0,0 +1,107 @@
+<?php namespace Laravel\Routing;
+
+use Laravel\Arr;
+
+class Loader {
+
+	/**
+	 * The location of the base routes file.
+	 *
+	 * @var string
+	 */
+	protected $base;
+
+	/**
+	 * The directory containing nested route files.
+	 *
+	 * @var string
+	 */
+	protected $nest;
+
+	/**
+	 * A cache for all of the routes defined for the entire application.
+	 *
+	 * @var array
+	 */
+	protected $everything;
+
+	/**
+	 * Create a new route loader instance.
+	 *
+	 * @param  string  $base
+	 * @param  string  $nest
+	 * @return void
+	 */
+	public function __construct($base, $nest)
+	{
+		$this->base = $base;
+		$this->nest = $nest;
+	}
+
+	/**
+	 * Load the applicable routes for a given URI.
+	 *
+	 * @param  string  $uri
+	 * @return array
+	 */
+	public function load($uri)
+	{
+		$routes = (file_exists($path = $this->base.'routes'.EXT)) ? require $path : array();
+
+		return array_merge($this->nested(Arr::without(explode('/', $uri), array(''))), $routes);
+	}
+
+	/**
+	 * Get the appropriate routes from the routes directory for a given URI.
+	 *
+	 * @param  array  $segments
+	 * @return array
+	 */
+	protected function nested($segments)
+	{
+		// Work backwards through the URI segments until we find the deepest possible
+		// matching route directory. Once we find it, we will return those routes.
+		foreach (array_reverse($segments, true) as $key => $value)
+		{
+			if (file_exists($path = $this->nest.implode('/', array_slice($segments, 0, $key + 1)).EXT))
+			{
+				return require $path;
+			}
+			elseif (file_exists($path = str_replace('.php', '/routes.php', $path)))
+			{
+				return require $path;
+			}
+		}
+
+		return array();
+	}
+
+	/**
+	 * Get every route defined for the application.
+	 *
+	 * @return array
+	 */
+	public function everything()
+	{
+		if ( ! is_null($this->everything)) return $this->everything;
+
+		$routes = array();
+
+		// Since route files can be nested deep within the route directory, we need to
+		// recursively spin through the directory to find every file.
+		$directoryIterator = new \RecursiveDirectoryIterator($this->nest);
+
+		$recursiveIterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);
+
+		foreach ($recursiveIterator as $file)
+		{
+			if (filetype($file) === 'file')
+			{
+				$routes = array_merge(require $file, $routes);
+			}
+		}
+
+		return $this->everything = $routes;
+	}
+
+}

+ 6 - 4
laravel/routing/route.php

@@ -95,11 +95,13 @@ class Route {
 		}
 
 		// Otherwise, we will assume the route is an array and will return the first value with
-		// a key of "do", or the first instance of a Closure. If the value is a string, the route
-		// is delegating the responsibility for handling the request to a controller.
+		// a key of "delegate", or the first instance of a Closure. If the value is a string, the
+		// route is delegating the responsibility for handling the request to a controller.
 		elseif (is_array($this->callback))
 		{
-			return Arr::first($this->callback, function($key, $value) {return $key == 'do' or $value instanceof Closure;});
+			$callback = Arr::first($this->callback, function($key, $value) {return $key == 'delegate' or $value instanceof Closure;});
+
+			return ($callback instanceof Closure) ? call_user_func_array($callback, $this->parameters) : new Delegate($callback);
 		}
 
 		// If a value defined for a route is a string, it means the route is delegating control
@@ -107,7 +109,7 @@ class Route {
 		// for the route caller to parse and delegate.
 		elseif (is_string($this->callback))
 		{
-			return $this->callback;
+			return new Delegate($this->callback);
 		}
 	}
 

+ 12 - 10
laravel/routing/router.php

@@ -5,11 +5,11 @@ use Laravel\Request;
 class Router {
 
 	/**
-	 * All of the routes available to the router.
+	 * The route loader instance.
 	 *
-	 * @var array
+	 * @var Loader
 	 */
-	public $routes;
+	public $loader;
 
 	/**
 	 * The named routes that have been found so far.
@@ -28,13 +28,13 @@ class Router {
 	/**
 	 * Create a new router for a request method and URI.
 	 *
-	 * @param  array   $routes
+	 * @param  Loader  $loader
 	 * @param  string  $controllers
 	 * @return void
 	 */
-	public function __construct($routes, $controllers)
+	public function __construct(Loader $loader, $controllers)
 	{
-		$this->routes = $routes;
+		$this->loader = $loader;
 		$this->controllers = $controllers;
 	}
 
@@ -50,7 +50,7 @@ class Router {
 	{
 		if (array_key_exists($name, $this->names)) return $this->names[$name];
 
-		$arrayIterator = new \RecursiveArrayIterator($this->routes);
+		$arrayIterator = new \RecursiveArrayIterator($this->loader->everything());
 
 		$recursiveIterator = new \RecursiveIteratorIterator($arrayIterator);
 
@@ -75,18 +75,20 @@ class Router {
 	 */
 	public function route(Request $request)
 	{
+		$routes = $this->loader->load($request->uri());
+
 		// Put the request method and URI in route form. Routes begin with
 		// the request method and a forward slash.
 		$destination = $request->method().' /'.trim($request->uri(), '/');
 
 		// Check for a literal route match first. If we find one, there is
 		// no need to spin through all of the routes.
-		if (isset($this->routes[$destination]))
+		if (isset($routes[$destination]))
 		{
-			return $request->route = new Route($destination, $this->routes[$destination], array());
+			return $request->route = new Route($destination, $routes[$destination], array());
 		}
 
-		foreach ($this->routes as $keys => $callback)
+		foreach ($routes as $keys => $callback)
 		{
 			// Only check routes that have multiple URIs or wildcards.
 			// Other routes would have been caught by the check for literal matches.

+ 240 - 39
laravel/security/hashing/bcrypt.php

@@ -1,53 +1,254 @@
 <?php namespace Laravel\Security\Hashing;
 
+#
+# Portable PHP password hashing framework.
+#
+# Version 0.3 / genuine.
+#
+# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
+# the public domain.  Revised in subsequent years, still public domain.
+#
+# There's absolutely no warranty.
+#
+# The homepage URL for this framework is:
+#
+#	http://www.openwall.com/phpass/
+#
+# Please be sure to update the Version line if you edit this file in any way.
+# It is suggested that you leave the main version number intact, but indicate
+# your project name (after the slash) and add your own revision information.
+#
+# Please do not change the "private" password hashing method implemented in
+# here, thereby making your hashes incompatible.  However, if you must, please
+# change the hash type identifier (the "$P$") to something different.
+#
+# Obviously, since this code is in the public domain, the above are not
+# requirements (there can be none), but merely suggestions.
+#
 class Bcrypt implements Engine {
+	var $itoa64;
+	var $iteration_count_log2;
+	var $portable_hashes;
+	var $random_state;
 
-	/**
-	 * The number of iterations that should be performed.
-	 *
-	 * @var int
-	 */
-	protected $rounds;
-
-	/**
-	 * Create a new bcrypt hashing engine.
-	 *
-	 * @param  int   $rounds
-	 * @return void
-	 */
-	public function __construct($rounds)
-	{
-		$this->rounds = $rounds;
-
-		if ( ! function_exists('openssl_random_pseudo_bytes'))
-		{
-			throw new \Exception("The openssl PHP extension is required to perform bcrypt hashing.");
+	public function __construct($iteration_count_log2, $portable_hashes)
+	{
+		$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+
+		if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
+			$iteration_count_log2 = 8;
+		$this->iteration_count_log2 = $iteration_count_log2;
+
+		$this->portable_hashes = $portable_hashes;
+
+		$this->random_state = microtime();
+		if (function_exists('getmypid'))
+			$this->random_state .= getmypid();
+	}
+
+	protected function get_random_bytes($count)
+	{
+		$output = '';
+		if (is_readable('/dev/urandom') &&
+		    ($fh = @fopen('/dev/urandom', 'rb'))) {
+			$output = fread($fh, $count);
+			fclose($fh);
 		}
+
+		if (strlen($output) < $count) {
+			$output = '';
+			for ($i = 0; $i < $count; $i += 16) {
+				$this->random_state =
+				    md5(microtime() . $this->random_state);
+				$output .=
+				    pack('H*', md5($this->random_state));
+			}
+			$output = substr($output, 0, $count);
+		}
+
+		return $output;
 	}
 
-	/**
-	 * Perform a one-way hash on a string using bcrypt.
-	 *
-	 * @param  string  $value
-	 * @return string
-	 */
-	public function hash($value)
+	protected function encode64($input, $count)
 	{
-		$salt = sprintf('$2a$%02d$', $this->rounds).substr(base64_encode(openssl_random_pseudo_bytes(16)), 0, 22);
+		$output = '';
+		$i = 0;
+		do {
+			$value = ord($input[$i++]);
+			$output .= $this->itoa64[$value & 0x3f];
+			if ($i < $count)
+				$value |= ord($input[$i]) << 8;
+			$output .= $this->itoa64[($value >> 6) & 0x3f];
+			if ($i++ >= $count)
+				break;
+			if ($i < $count)
+				$value |= ord($input[$i]) << 16;
+			$output .= $this->itoa64[($value >> 12) & 0x3f];
+			if ($i++ >= $count)
+				break;
+			$output .= $this->itoa64[($value >> 18) & 0x3f];
+		} while ($i < $count);
+
+		return $output;
+	}
+
+	protected function gensalt_private($input)
+	{
+		$output = '$P$';
+		$output .= $this->itoa64[min($this->iteration_count_log2 +
+			((PHP_VERSION >= '5') ? 5 : 3), 30)];
+		$output .= $this->encode64($input, 6);
+
+		return $output;
+	}
+
+	protected function crypt_private($password, $setting)
+	{
+		$output = '*0';
+		if (substr($setting, 0, 2) == $output)
+			$output = '*1';
+
+		$id = substr($setting, 0, 3);
+		# We use "$P$", phpBB3 uses "$H$" for the same thing
+		if ($id != '$P$' && $id != '$H$')
+			return $output;
+
+		$count_log2 = strpos($this->itoa64, $setting[3]);
+		if ($count_log2 < 7 || $count_log2 > 30)
+			return $output;
+
+		$count = 1 << $count_log2;
+
+		$salt = substr($setting, 4, 8);
+		if (strlen($salt) != 8)
+			return $output;
+
+		# We're kind of forced to use MD5 here since it's the only
+		# cryptographic primitive available in all versions of PHP
+		# currently in use.  To implement our own low-level crypto
+		# in PHP would result in much worse performance and
+		# consequently in lower iteration counts and hashes that are
+		# quicker to crack (by non-PHP code).
+		if (PHP_VERSION >= '5') {
+			$hash = md5($salt . $password, TRUE);
+			do {
+				$hash = md5($hash . $password, TRUE);
+			} while (--$count);
+		} else {
+			$hash = pack('H*', md5($salt . $password));
+			do {
+				$hash = pack('H*', md5($hash . $password));
+			} while (--$count);
+		}
+
+		$output = substr($setting, 0, 12);
+		$output .= $this->encode64($hash, 16);
 
-		return crypt($value, str_replace('+', '.', $salt));
+		return $output;
 	}
 
-	/**
-	 * Determine if an unhashed value matches a given hash.
-	 *
-	 * @param  string  $value
-	 * @param  string  $hash
-	 * @return bool
-	 */
-	public function check($value, $hash)
+	protected function gensalt_extended($input)
 	{
-		return crypt($value, $hash) === $hash;
+		$count_log2 = min($this->iteration_count_log2 + 8, 24);
+		# This should be odd to not reveal weak DES keys, and the
+		# maximum valid value is (2**24 - 1) which is odd anyway.
+		$count = (1 << $count_log2) - 1;
+
+		$output = '_';
+		$output .= $this->itoa64[$count & 0x3f];
+		$output .= $this->itoa64[($count >> 6) & 0x3f];
+		$output .= $this->itoa64[($count >> 12) & 0x3f];
+		$output .= $this->itoa64[($count >> 18) & 0x3f];
+
+		$output .= $this->encode64($input, 3);
+
+		return $output;
+	}
+
+	protected function gensalt_blowfish($input)
+	{
+		# This one needs to use a different order of characters and a
+		# different encoding scheme from the one in encode64() above.
+		# We care because the last character in our encoded string will
+		# only represent 2 bits.  While two known implementations of
+		# bcrypt will happily accept and correct a salt string which
+		# has the 4 unused bits set to non-zero, we do not want to take
+		# chances and we also do not want to waste an additional byte
+		# of entropy.
+		$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+		$output = '$2a$';
+		$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
+		$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
+		$output .= '$';
+
+		$i = 0;
+		do {
+			$c1 = ord($input[$i++]);
+			$output .= $itoa64[$c1 >> 2];
+			$c1 = ($c1 & 0x03) << 4;
+			if ($i >= 16) {
+				$output .= $itoa64[$c1];
+				break;
+			}
+
+			$c2 = ord($input[$i++]);
+			$c1 |= $c2 >> 4;
+			$output .= $itoa64[$c1];
+			$c1 = ($c2 & 0x0f) << 2;
+
+			$c2 = ord($input[$i++]);
+			$c1 |= $c2 >> 6;
+			$output .= $itoa64[$c1];
+			$output .= $itoa64[$c2 & 0x3f];
+		} while (1);
+
+		return $output;
+	}
+
+	public function hash($password)
+	{
+		$random = '';
+
+		if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
+			$random = $this->get_random_bytes(16);
+			$hash =
+			    crypt($password, $this->gensalt_blowfish($random));
+			if (strlen($hash) == 60)
+				return $hash;
+		}
+
+		if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
+			if (strlen($random) < 3)
+				$random = $this->get_random_bytes(3);
+			$hash =
+			    crypt($password, $this->gensalt_extended($random));
+			if (strlen($hash) == 20)
+				return $hash;
+		}
+
+		if (strlen($random) < 6)
+			$random = $this->get_random_bytes(6);
+		$hash =
+		    $this->crypt_private($password,
+		    $this->gensalt_private($random));
+		if (strlen($hash) == 34)
+			return $hash;
+
+		# Returning '*' on error is safe here, but would _not_ be safe
+		# in a crypt(3)-like function used _both_ for generating new
+		# hashes and for validating passwords against existing hashes.
+		return '*';
+	}
+
+	public function check($password, $stored_hash)
+	{
+		$hash = $this->crypt_private($password, $stored_hash);
+		if ($hash[0] == '*')
+			$hash = crypt($password, $stored_hash);
+
+		return $hash == $stored_hash;
 	}
+}
 
-}
+?>

+ 2 - 5
laravel/session/transporters/cookie.php

@@ -33,12 +33,9 @@ class Cookie implements Transporter {
 	 */
 	public function put($id, $config)
 	{
-		if ( ! headers_sent())
-		{
-			$minutes = ($config['expire_on_close']) ? 0 : $config['lifetime'];
+		$minutes = ($config['expire_on_close']) ? 0 : $config['lifetime'];
 
-			$this->cookie->put('laravel_session', $id, $minutes, $config['path'], $config['domain']);
-		}
+		$this->cookie->put('laravel_session', $id, $minutes, $config['path'], $config['domain']);
 	}
 
 }

+ 1 - 1
tests/bootstrap.php

@@ -23,4 +23,4 @@ $storage     = 'storage';
 
 $public      = 'public';
 
-require realpath($laravel).'/bootstrap.php';
+require realpath($laravel).'/core.php';