From df9130dafa4c7f44dbc19e9b589793cfb76000da Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 19 Oct 2011 22:44:02 -0500 Subject: [PATCH] refactoring and working on redis. --- laravel/bootstrap/constants.php | 26 ++--- laravel/bootstrap/errors.php | 17 ++- laravel/cache/drivers/memcached.php | 2 +- laravel/database/grammars/grammar.php | 20 +++- laravel/database/manager.php | 2 +- laravel/redis.php | 155 ++++++++++++++++++++++++++ laravel/security/crypter.php | 39 +++---- laravel/session/manager.php | 12 +- 8 files changed, 224 insertions(+), 49 deletions(-) create mode 100644 laravel/redis.php diff --git a/laravel/bootstrap/constants.php b/laravel/bootstrap/constants.php index d6dd3b20..4b331d3a 100644 --- a/laravel/bootstrap/constants.php +++ b/laravel/bootstrap/constants.php @@ -1,16 +1,13 @@ realpath($application).'/', @@ -37,8 +34,9 @@ function constants($constants) constants($constants); /** - * Register all of the other framework paths. All of these - * paths are built on top of the core paths above. + * Register all of the other framework paths. All of these paths + * are built on top of the core paths above. We still allow the + * developer to override these for easy unit testing. */ $constants = array( 'CACHE_PATH' => STORAGE_PATH.'cache/', @@ -63,7 +61,7 @@ function constants($constants) /** * Set the Laravel environment configuration path constant. - * The environment is controller by setting an environment + * The environment is controlled by setting an environment * variable on the server running Laravel. */ $environment = (isset($_SERVER['LARAVEL_ENV'])) ? $_SERVER['LARAVEL_ENV'] : ''; diff --git a/laravel/bootstrap/errors.php b/laravel/bootstrap/errors.php index 51b0529e..877175e3 100644 --- a/laravel/bootstrap/errors.php +++ b/laravel/bootstrap/errors.php @@ -59,20 +59,31 @@ }; /** - * Register the PHP exception, error, and shutdown error handlers. - * These handlers will catch all PHP exceptions and errors and pass - * the exceptions into the common Laravel error handler. + * Register the PHP exception handler. The framework throws exceptions + * on every error that cannot be handled. All of those exceptions will + * fall into this closure for processing. */ set_exception_handler(function($e) use ($handler) { $handler($e); }); +/** + * Register the PHP error handler. All PHP errors will fall into this + * handler, which will convert the error into an ErrorException object + * and pass the exception into the common exception handler. + */ set_error_handler(function($number, $error, $file, $line) use ($handler) { $handler(new \ErrorException($error, $number, 0, $file, $line)); }); +/** + * Register the PHP shutdown handler. This function will be called at + * the end of the PHP script or on a fatal PHP error. If an error has + * occurred, we will convert it to an ErrorException and pass it to + * the common exception handler. + */ register_shutdown_function(function() use ($handler) { if ( ! is_null($error = error_get_last())) diff --git a/laravel/cache/drivers/memcached.php b/laravel/cache/drivers/memcached.php index a581d973..44497b61 100644 --- a/laravel/cache/drivers/memcached.php +++ b/laravel/cache/drivers/memcached.php @@ -1,4 +1,4 @@ -columnize(array_keys(reset($values))); - // We need to create a string of comma-delimited insert segments. Each segment - // contains PDO place-holders for each value being inserted into the table. - $parameters = implode(', ', array_fill(0, count($values), '('.$this->parameterize(reset($values)).')')); + // Build the list of parameter place-holders for the array of values bound + // to the query. Each insert statement should have the same number of bound + // parameters, so we can just use the first array of values. + $parameters = $this->parameterize(reset($values)); + + $parameters = implode(', ', array_fill(0, count($values), '('.$parameters.')')); return 'INSERT INTO '.$this->wrap($query->from).' ('.$columns.') VALUES '.$parameters; } diff --git a/laravel/database/manager.php b/laravel/database/manager.php index 835d1aaa..f50f3411 100644 --- a/laravel/database/manager.php +++ b/laravel/database/manager.php @@ -40,7 +40,7 @@ public static function connection($connection = null) if (is_null($config)) { - throw new \Exception("Database connection configuration is not defined for connection [$connection]."); + throw new \Exception("Database connection is not defined for connection [$connection]."); } static::$connections[$connection] = new Connection(static::connect($config), $config); diff --git a/laravel/redis.php b/laravel/redis.php new file mode 100644 index 00000000..cf5f8dc5 --- /dev/null +++ b/laravel/redis.php @@ -0,0 +1,155 @@ +name = $name; + $this->config = $config; + } + + /** + * Create a new Redis connection instance. + * + * @param string $connection + * @param array $config + * @return Redis + */ + public static function make($name, $config) + { + return new static($name, $config); + } + + /** + * Create a new Redis connection instance. + * + * Redis connections are managed as singletons, so if the connection has + * already been established, that same connection instance will be returned + * on subsequent requests for the connection. + * + * @param string $connection + * @return Redis + */ + public static function connection($name) + { + if ( ! array_key_exists($name, static::$connections)) + { + $config = Config::get("database.redis.{$name}"); + + if (is_null($config)) + { + throw new \Exception("Redis connection [$name] has not been configured."); + } + + static::$connections[$name] = static::make($name, $config)->connect(); + } + + return static::$connections[$name]; + } + + /** + * Connect to the Redis database. + * + * The Redis instance itself will be returned by the method. + * + * @return Redis + */ + public function connect() + { + $this->connection = @fsockopen($this->config['host'], $this->config['port'], $error, $message); + + if ($this->connection === false) + { + throw new \Exception("Error establishing Redis connection [{$this->name}]: {$error} - {$message}"); + } + + return $this; + } + + /** + * Execute a command agaisnt the Redis database. + * + * @param string $method + * @param array $parameters + * @return mixed + */ + public function do($method, $parameters) + { + fwrite($this->connection, $this->command($method, $parameters)); + + $reply = trim(fgets($this->connection, 512)); + } + + /** + * Build the Redis command based from a given method and parameters. + * + * @param string $method + * @param array $parameters + * @return string + */ + protected function command($method, $parameters) + { + $command = '*'.(count($parameters) + 1).CRLF.'$'.strlen($method).CRLF.strtoupper($method).CRLF; + + foreach ($parameters as $parameter) + { + $command .= '$'.strlen($parameter).CRLF.$parameter.CRLF; + } + + return $command; + } + + /** + * Dynamically make calls to the Redis database. + */ + public function __call($method, $parameters) + { + return $this->do($method, $parameters); + } + + /** + * Close the connection to the Redis database. + * + * @return void + */ + public function __destruct() + { + fclose($this->connection); + } + +} \ No newline at end of file diff --git a/laravel/security/crypter.php b/laravel/security/crypter.php index 6312f900..1475e09a 100644 --- a/laravel/security/crypter.php +++ b/laravel/security/crypter.php @@ -54,52 +54,43 @@ public static function encrypt($value) $iv = mcrypt_create_iv(static::iv_size(), $randomizer); - $key = Config::$items['application']['key']; - - return base64_encode($iv.mcrypt_encrypt(static::$cipher, $key, $value, static::$mode, $iv)); + return base64_encode($iv.mcrypt_encrypt(static::$cipher, static::key(), $value, static::$mode, $iv)); } /** * Decrypt a string using Mcrypt. * - * - * // Decrypt a string using the Mcrypt PHP extension - * $decrypted = Crypter::decrypt($secret); - * - * * @param string $value * @return string */ public static function decrypt($value) { - if ( ! is_string($value = base64_decode($value, true))) - { - throw new \Exception('Decryption error. Input value is not valid base64 data.'); - } + list($iv, $value) = static::parse(base64_decode($value, true)); - list($iv, $value) = static::parse($value); - - $key = Config::$items['application']['key']; - - return rtrim(mcrypt_decrypt(static::$cipher, $key, $value, static::$mode, $iv), "\0"); + return rtrim(mcrypt_decrypt(static::$cipher, static::key(), $value, static::$mode, $iv), "\0"); } /** * Parse an encrypted value into the input vector and the actual value. * + * If the given value is not valid base64 data, an exception will be thrown. + * * @param string $value * @return array */ protected static function parse($value) { + if ( ! is_string($value)) + { + throw new \Exception('Decryption error. Input value is not valid base64 data.'); + } + return array(substr($value, 0, static::iv_size()), substr($value, static::iv_size())); } /** * Get the input vector size for the cipher and mode. * - * Different ciphers and modes use varying lengths of input vectors. - * * @return int */ protected static function iv_size() @@ -107,4 +98,14 @@ protected static function iv_size() return mcrypt_get_iv_size(static::$cipher, static::$mode); } + /** + * Get the encryption key from the application configuration. + * + * @return string + */ + protected static function key() + { + return Config::$items['application']['key']; + } + } \ No newline at end of file diff --git a/laravel/session/manager.php b/laravel/session/manager.php index 30baf671..adf43336 100644 --- a/laravel/session/manager.php +++ b/laravel/session/manager.php @@ -67,15 +67,13 @@ public static function start(Driver $driver, Transporter $transporter) $session = array('id' => Str::random(40), 'data' => array()); } + // Now that we should have a valid session, we can set the static session + // property and check for session data such as the CSRF token. We will + // also set the static driver and transporter properties, since they + // will be used to close the session at the end of the request. static::$session = $session; - // If a CSRF token is not present in the session, we will generate one. - // These tokens are generated per session to protect against Cross-Site - // Request Forgery attacks on the application. - if ( ! static::has('csrf_token')) - { - static::put('csrf_token', Str::random(16)); - } + if ( ! static::has('csrf_token')) static::put('csrf_token', Str::random(16)); list(static::$driver, static::$transporter) = array($driver, $transporter); }