Merge pull request #1 from laravel/master

merge
This commit is contained in:
尘缘 2013-05-04 06:41:24 -07:00
commit f742cc32f5
70 changed files with 1530 additions and 278 deletions

View File

@ -159,6 +159,7 @@
'Blade' => 'Laravel\\Blade',
'Bundle' => 'Laravel\\Bundle',
'Cache' => 'Laravel\\Cache',
'Command' => 'Laravel\\CLI\\Command',
'Config' => 'Laravel\\Config',
'Controller' => 'Laravel\\Routing\\Controller',
'Cookie' => 'Laravel\\Cookie',

View File

@ -0,0 +1,19 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the pagination links. You're free to change them to anything you want.
| If you come up with something more exciting, let us know.
|
*/
'previous' => '&laquo; Inapoi',
'next' => 'Inainte &raquo;',
);

View File

@ -0,0 +1,106 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used
| by the validator class. Some of the rules contain multiple versions,
| such as the size (max, min, between) rules. These versions are used
| for different input types such as strings and files.
|
| These language lines may be easily changed to provide custom error
| messages in your application. Error messages for custom validation
| rules may also be added to this file.
|
*/
"accepted" => "Campul :attribute trebuie sa fie acceptat.",
"active_url" => "Campul :attribute nu este un URL valid.",
"after" => "Campul :attribute trebuie sa fie o data dupa :date.",
"alpha" => "Campul :attribute poate contine numai litere.",
"alpha_dash" => "Campul :attribute poate contine numai litere, numere si liniute.",
"alpha_num" => "Campul :attribute poate contine numai litere si numere.",
"array" => "Campul :attribute trebuie sa aiba elemente selectate.",
"before" => "Campul :attribute trebuie sa fie o data inainte de :date.",
"between" => array(
"numeric" => "Campul :attribute trebuie sa fie intre :min si :max.",
"file" => "Campul :attribute trebuie sa fie intre :min si :max kilobytes.",
"string" => "Campul :attribute trebuie sa fie intre :min si :max caractere.",
),
"confirmed" => "Confirmarea :attribute nu se potriveste.",
"count" => "Campul :attribute trebuie sa aiba exact :count elemente selectate.",
"countbetween" => "Campul :attribute trebuie sa aiba intre :min si :max elemente selectate.",
"countmax" => "Campul :attribute trebuie sa aiba mai putin de :max elemente selectate.",
"countmin" => "Campul :attribute trebuie sa aiba cel putin :min elemente selectate.",
"date_format" => "Campul :attribute trebuie sa fie intr-un format valid.",
"different" => "Campurile :attribute si :other trebuie sa fie diferite.",
"email" => "Formatul campului :attribute este invalid.",
"exists" => "Campul :attribute selectat este invalid.",
"image" => "Campul :attribute trebuie sa fie o imagine.",
"in" => "Campul :attribute selectat este invalid.",
"integer" => "Campul :attribute trebuie sa fie un numar intreg.",
"ip" => "Campul :attribute trebuie sa fie o adresa IP valida.",
"match" => "Formatul campului :attribute este invalid.",
"max" => array(
"numeric" => "Campul :attribute trebuie sa fie mai mic de :max.",
"file" => "Campul :attribute trebuie sa fie mai mic de :max kilobytes.",
"string" => "Campul :attribute trebuie sa fie mai mic de :max caractere.",
),
"mimes" => "Campul :attribute trebuie sa fie un fisier de tipul: :values.",
"min" => array(
"numeric" => "Campul :attribute trebuie sa fie cel putin :min.",
"file" => "Campul :attribute trebuie sa aiba cel putin :min kilobytes.",
"string" => "Campul :attribute trebuie sa aiba cel putin :min caractere.",
),
"not_in" => "Campul :attribute selectat este invalid.",
"numeric" => "Campul :attribute trebuie sa fie un numar.",
"required" => "Campul :attribute este obligatoriu.",
"required_with" => "Campul :attribute este obligatoriu cu :field",
"same" => "Campul :attribute si :other trebuie sa fie identice.",
"size" => array(
"numeric" => "Campul :attribute trebuie sa fie :size.",
"file" => "Campul :attribute trebuie sa aiba :size kilobyte.",
"string" => "Campul :attribute trebuie sa aiba :size caractere.",
),
"unique" => "Campul :attribute a fost deja folosit.",
"url" => "Campul :attribute nu este intr-un format valid.",
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute_rule" to name the lines. This helps keep your
| custom validation clean and tidy.
|
| So, say you want to use a custom validation message when validating that
| the "email" attribute is unique. Just add "email_unique" to this array
| with your custom message. The Validator will handle the rest!
|
*/
'custom' => array(),
/*
|--------------------------------------------------------------------------
| Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as "E-Mail Address" instead
| of "email". Your users will thank you.
|
| The Validator class will automatically search this array of lines it
| is attempting to replace the :attribute place-holder in messages.
| It's pretty slick. We think you'll like it.
|
*/
'attributes' => array(),
);

View File

@ -48,7 +48,8 @@
|
| Similarly, we use an event to handle the display of 500 level errors
| within the application. These errors are fired when there is an
| uncaught exception thrown in the application.
| uncaught exception thrown in the application. The exception object
| that is captured during execution is then passed to the 500 listener.
|
*/
@ -57,7 +58,7 @@
return Response::error('404');
});
Event::listen('500', function()
Event::listen('500', function($exception)
{
return Response::error('500');
});

View File

@ -3,7 +3,7 @@
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @version 3.2.13
* @version 3.2.14
* @author Taylor Otwell <taylorotwell@gmail.com>
* @link http://laravel.com
*/

View File

@ -215,7 +215,7 @@ protected function token()
*/
protected function recaller()
{
return $this->name().'_remember';
return Config::get('auth.cookie', $this->name().'_remember');
}
/**

View File

@ -97,4 +97,14 @@ public function forget($key)
if (file_exists($this->path.$key)) @unlink($this->path.$key);
}
/**
* Flush the entire cache.
*
* @return void
*/
public function flush()
{
array_map('unlink', glob($this->path.'*'));
}
}

View File

@ -88,4 +88,14 @@ public function forget($key)
$this->redis->del($key);
}
/**
* Flush the entire cache.
*
* @return void
*/
public function flush()
{
$this->redis->flushdb();
}
}

View File

@ -43,7 +43,8 @@
}
catch (\Exception $e)
{
echo $e->getMessage();
echo $e->getMessage().PHP_EOL;
exit(1);
}
echo PHP_EOL;

View File

@ -88,7 +88,7 @@ protected function test()
// strings with spaces inside should be wrapped in quotes.
$esc_path = escapeshellarg($path);
passthru('phpunit --configuration '.$esc_path, $status);
passthru('LARAVEL_ENV='.Request::env().' phpunit --configuration '.$esc_path, $status);
@unlink($path);

View File

@ -82,6 +82,10 @@ public static function put($name, $value, $expiration = 0, $path = '/', $domain
$value = static::hash($value).'+'.$value;
// If the developer has explicitly disabled SLL, then we shouldn't force
// this cookie over SSL.
$secure = $secure && Config::get('application.ssl');
// If the secure option is set to true, yet the request is not over HTTPS
// we'll throw an exception to let the developer know that they are
// attempting to send a secure cookie over the insecure HTTP.

View File

@ -138,7 +138,7 @@ protected static function unpad($value)
$pad = ord(substr($value, -1));
}
if ($pad and $pad < static::$block)
if ($pad and $pad <= static::$block)
{
// If the correct padding is present on the string, we will remove
// it and return the value. Otherwise, we'll throw an exception

View File

@ -75,7 +75,8 @@ protected function grammar()
if (isset(\Laravel\Database::$registrar[$this->driver()]))
{
return $this->grammar = \Laravel\Database::$registrar[$this->driver()]['query']();
$resolver = \Laravel\Database::$registrar[$this->driver()]['query'];
return $this->grammar = $resolver($this);
}
switch ($this->driver())
@ -308,7 +309,7 @@ protected function fetch($statement, $style)
*/
protected function log($sql, $bindings, $start)
{
$time = number_format((microtime(true) - $start) * 1000, 2);
$time = (microtime(true) - $start) * 1000;
Event::fire('laravel.query', array($sql, $bindings, $time));

View File

@ -517,7 +517,7 @@ public function get_dirty()
foreach ($this->attributes as $key => $value)
{
if ( ! array_key_exists($key, $this->original) or $value != $this->original[$key])
if ( ! array_key_exists($key, $this->original) or $value !== $this->original[$key])
{
$dirty[$key] = $value;
}

View File

@ -829,7 +829,9 @@ public function insert_get_id($values, $column = 'id')
}
else if ($this->grammar instanceof Postgres)
{
return (int) $result[0]->$column;
$row = (array) $result[0];
return (int) $row[$column];
}
else
{

View File

@ -39,6 +39,25 @@ class Table {
*/
public $commands = array();
/**
* The registered custom macros.
*
* @var array
*/
public static $macros = array();
/**
* Registers a custom macro.
*
* @param string $name
* @param Closure $macro
* @return void
*/
public static function macro($name, $macro)
{
static::$macros[$name] = $macro;
}
/**
* Create a new schema table instance.
*
@ -422,4 +441,22 @@ protected function column($type, $parameters = array())
return $this->columns[] = new Fluent($parameters);
}
/**
* Dynamically handle calls to custom macros.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (isset(static::$macros[$method]))
{
array_unshift($parameters, $this);
return call_user_func_array(static::$macros[$method], $parameters);
}
throw new \Exception("Method [$method] does not exist.");
}
}

View File

@ -2,6 +2,8 @@ # Laravel Change Log
## Contents
- [Laravel 3.2.14](#3.2.14)
- [Upgrading From 3.2.13](#upgrade-3.2.14)
- [Laravel 3.2.13](#3.2.13)
- [Upgrading From 3.2.12](#upgrade-3.2.13)
- [Laravel 3.2.12](#3.2.12)
@ -51,6 +53,17 @@ ## Contents
- [Laravel 3.1](#3.1)
- [Upgrading From 3.0](#upgrade-3.1)
<a name="3.2.14"></a>
## Laravel 3.2.14
- IoC can now resolve default parameters.
- Fix bug in Postgres insert_get_id when using FETCH_ASSOC.
<a name="upgrade-3.2.14"></a>
### Upgrading From 3.2.13
- Replace the **laravel** folder.
<a name="3.2.13"></a>
## Laravel 3.2.13

View File

@ -88,7 +88,7 @@ ## Committing
# git commit -s -m "I added some more stuff to the Localization documentation."
- **-s** means that you are signing-off on your commit with your name. This tells the Laravel team know that you personally agree to your code being added to the Laravel core.
- **-s** means that you are signing-off on your commit with your name. This lets the Laravel team know that you personally agree to your code being added to the Laravel core.
- **-m** is the message that goes with your commit. Provide a brief explanation of what you added or changed.
<a name="pushing-to-your-fork"></a>

View File

@ -76,7 +76,7 @@ ## Creating Branches
- Right-click the Laravel directory and goto **Git Commit -> "feature/localization-docs"…**
- Commit
- **Message:** Provide a brief explaination of what you added or changed
- Click **Sign** - This tells the Laravel team know that you personally agree to your code being added to the Laravel core
- Click **Sign** - This lets the Laravel team know that you personally agree to your code being added to the Laravel core
- **Changes made:** Check all changed/added files
- Click **OK**

View File

@ -98,7 +98,7 @@ #### Attaching a filter to all except a few actions:
$this->filter('before', 'auth')->except(array('add', 'posts'));
Much like the previous example, this declaration ensures that the auth filter is run on only some of this controller's actions. Instead of declaring to which actions the filter applies we are instead declaring the actions that will not require authenticated sessions. It can sometimes be safer to use the 'except' method as it's possible to add new actions to this controller and to forget to add them to only(). This could potentially lead your controller's action being unintentionally accessible by users who haven't been authenticated.
Much like the previous example, this declaration ensures that the auth filter is run on only some of this controller's actions. Instead of declaring to which actions the filter applies we are instead declaring the actions that will not require authenticated sessions. It can sometimes be safer to use the 'except' method as it's possible to add new actions to this controller and to forget to add them to only(). This could potentially lead to your controller's action being unintentionally accessible by users who haven't been authenticated.
#### Attaching a filter to run on POST:

View File

@ -284,7 +284,7 @@ ### Many-To-Many
$roles = User::find(1)->roles;
If your table names don't follow conventions, simply pass the table name in the second parameter to the **has\_and\_belongs\_to\_many** method:
If your table names don't follow conventions, simply pass the table name in the second parameter to the **has\_many\_and\_belongs\_to** method:
class User extends Eloquent {

View File

@ -76,6 +76,13 @@ ### where and or\_where
->or_where('email', '=', 'example@gmail.com')
->first();
To do the equivalent of an AND where, simply chain the query with another where:
return DB::table('users')
->where('id', '=', 1)
->where('activated', '=', 1)
->first();
Of course, you are not limited to simply checking equality. You may also use **greater-than**, **less-than**, **not-equal**, and **like**:
return DB::table('users')

View File

@ -47,3 +47,12 @@ ## Resolving Objects
$mailer = IoC::resolve('mailer');
> **Note:** You may also [register controllers in the container](/docs/controllers#dependency-injection).
<a name="unregister"></a>
## Unregister an existing instance
For test purposes sometimes you need to unregister some container.
#### Unregister example mail class:
IoC::unregister('mailer');

View File

@ -83,6 +83,14 @@ #### Specifying extra HTML attributes for a label:
echo Form::label('email', 'E-Mail Address', array('class' => 'awesome'));
#### Turning off HTML escaping of label contents:
echo Form::label('confirm', 'Are you <strong>sure</strong> you want to proceed?', null, false);
You can pass ```false``` as the optional fourth argument to disable automatic HTML escaping of the label content.
> **Note:** After creating a label, any form element you create with a name matching the label name will automatically receive an ID matching the label name as well.
<a name="text"></a>

View File

@ -54,7 +54,7 @@ public static function exception($exception, $trace = true)
// Using events gives the developer more freedom.
else
{
$response = Event::first('500');
$response = Event::first('500', array($exception));
$response = Response::prepare($response);
}

View File

@ -182,13 +182,15 @@ public static function token()
* @param array $attributes
* @return string
*/
public static function label($name, $value, $attributes = array())
public static function label($name, $value, $attributes = array(), $escape_html = true)
{
static::$labels[] = $name;
$attributes = HTML::attributes($attributes);
$value = HTML::entities($value);
if ($escape_html) {
$value = HTML::entities($value);
}
return '<label for="'.$name.'"'.$attributes.'>'.$value.'</label>';
}

View File

@ -328,7 +328,7 @@ function head($array)
*/
function url($url = '', $https = null)
{
return Laravel\URL::to($url, $https);
return URL::to($url, $https);
}
/**
@ -340,7 +340,7 @@ function url($url = '', $https = null)
*/
function asset($url, $https = null)
{
return Laravel\URL::to_asset($url, $https);
return URL::to_asset($url, $https);
}
/**
@ -360,7 +360,7 @@ function asset($url, $https = null)
*/
function action($action, $parameters = array())
{
return Laravel\URL::to_action($action, $parameters);
return URL::to_action($action, $parameters);
}
/**
@ -380,7 +380,7 @@ function action($action, $parameters = array())
*/
function route($name, $parameters = array())
{
return Laravel\URL::to_route($name, $parameters);
return URL::to_route($name, $parameters);
}
/**
@ -523,7 +523,7 @@ function view($view, $data = array())
{
if (is_null($view)) return '';
return Laravel\View::make($view, $data);
return View::make($view, $data);
}
/**
@ -537,7 +537,7 @@ function render($view, $data = array())
{
if (is_null($view)) return '';
return Laravel\View::make($view, $data)->render();
return View::make($view, $data)->render();
}
/**
@ -551,7 +551,7 @@ function render($view, $data = array())
*/
function render_each($partial, array $data, $iterator, $empty = 'raw|')
{
return Laravel\View::render_each($partial, $data, $iterator, $empty);
return View::render_each($partial, $data, $iterator, $empty);
}
/**
@ -562,7 +562,7 @@ function render_each($partial, array $data, $iterator, $empty = 'raw|')
*/
function yield($section)
{
return Laravel\Section::yield($section);
return Section::yield($section);
}
/**

View File

@ -40,6 +40,8 @@ public static function all()
*/
public static function has($key)
{
if (is_array(static::get($key))) return true;
return trim((string) static::get($key)) !== '';
}

View File

@ -31,6 +31,19 @@ public static function register($name, $resolver = null, $singleton = false)
static::$registry[$name] = compact('resolver', 'singleton');
}
/**
* Unregister an object
*
* @param string $name
*/
public static function unregister($name)
{
if (array_key_exists($name, static::$registry)) {
unset(static::$registry[$name]);
unset(static::$singletons[$name]);
}
}
/**
* Determine if an object has been registered in the container.
*
@ -39,7 +52,7 @@ public static function register($name, $resolver = null, $singleton = false)
*/
public static function registered($name)
{
return array_key_exists($name, static::$registry);
return array_key_exists($name, static::$registry) || array_key_exists($name, static::$singletons);
}
/**
@ -141,6 +154,7 @@ public static function resolve($type, $parameters = array())
* @param string $type
* @param array $parameters
* @return mixed
* @throws \Exception
*/
protected static function build($type, $parameters = array())
{
@ -218,6 +232,7 @@ protected static function dependencies($parameters, $arguments)
*
* @param ReflectionParameter
* @return default value
* @throws \Exception
*/
protected static function resolveNonClass($parameter)
{

View File

@ -56,7 +56,31 @@ public static function write($type, $message, $pretty_print = false)
Event::fire('laravel.log', array($type, $message));
}
$message = static::format($type, $message);
$trace=debug_backtrace();
foreach($trace as $item)
{
if (isset($item['class']) AND $item['class'] == __CLASS__)
{
continue;
}
$caller = $item;
break;
}
$function = $caller['function'];
if (isset($caller['class']))
{
$class = $caller['class'] . '::';
}
else
{
$class = '';
}
$message = static::format($type, $class . $function . ' - ' . $message);
File::append(path('storage').'logs/'.date('Y-m-d').'.log', $message);
}

View File

@ -148,7 +148,7 @@ public static function query($sql, $bindings, $time)
$binding = Database::escape($binding);
$sql = preg_replace('/\?/', $binding, $sql, 1);
$sql = htmlspecialchars($sql);
$sql = htmlspecialchars($sql, ENT_QUOTES, 'UTF-8', false);
}
static::$data['queries'][] = array($sql, $time);

View File

@ -36,7 +36,7 @@
@foreach ($queries as $query)
<tr>
<td class="anbu-table-first">
{{ $query[1] }}ms
{{ number_format($query[1], 2) }}ms
</td>
<td>
<pre>{{ $query[0] }}</pre>
@ -103,7 +103,7 @@
<a data-anbu-tab="anbu-sql" class="anbu-tab" href="#">SQL
<span class="anbu-count">{{ count($queries) }}</span>
@if (count($queries))
<span class="anbu-count">{{ array_sum(array_map(function($q) { return $q[1]; }, $queries)) }}ms</span>
<span class="anbu-count">{{ number_format(array_sum(array_pluck($queries, '1')), 2) }}ms</span>
@endif
</a>
</li>

View File

@ -16,6 +16,13 @@ class Redis {
*/
protected $port;
/**
* The database password, if present.
*
* @var string
*/
protected $password;
/**
* The database number the connection selects on load.
*
@ -45,10 +52,11 @@ class Redis {
* @param int $database
* @return void
*/
public function __construct($host, $port, $database = 0)
public function __construct($host, $port, $password = null, $database = 0)
{
$this->host = $host;
$this->port = $port;
$this->password = $password;
$this->database = $database;
}
@ -79,7 +87,12 @@ public static function db($name = 'default')
extract($config);
static::$databases[$name] = new static($host, $port, $database);
if ( ! isset($password))
{
$password = null;
}
static::$databases[$name] = new static($host, $port, $password, $database);
}
return static::$databases[$name];
@ -153,6 +166,11 @@ protected function connect()
throw new \Exception("Error making Redis connection: {$error} - {$message}");
}
if ( $this->password )
{
$this->auth($this->password);
}
$this->select($this->database);
return $this->connection;

View File

@ -196,7 +196,7 @@ public static function time()
*/
public static function cli()
{
return defined('STDIN') || (substr(PHP_SAPI, 0, 3) == 'cgi' && getenv('TERM'));
return defined('STDIN') || (PHP_SAPI != "cgi-fcgi" && substr(PHP_SAPI, 0, 3) == 'cgi' && getenv('TERM'));
}
/**

View File

@ -276,7 +276,7 @@ public function execute($method, $parameters = array())
// Again, as was the case with route closures, if the controller "before"
// filters return a response, it will be considered the response to the
// request and the controller method will not be used.
$response = Filter::run($filters, array(), true);
$response = Filter::run($filters, $parameters, true);
if (is_null($response))
{

View File

@ -330,6 +330,18 @@ public static function put($route, $action)
Router::register('PUT', $route, $action);
}
/**
* Register a PATCH route with the router.
*
* @param string|array $route
* @param mixed $action
* @return void
*/
public static function patch($route, $action)
{
Router::register('PATCH', $route, $action);
}
/**
* Register a DELETE route with the router.
*

View File

@ -39,7 +39,7 @@ public function save($session, $config, $exists)
$payload = Crypter::encrypt(serialize($session));
C::put(Cookie::payload, $payload, $lifetime, $path, $domain);
C::put(Cookie::payload, $payload, $lifetime, $path, $domain, $secure);
}
/**

View File

@ -111,9 +111,11 @@ public function testFormLabel()
{
$form1 = Form::label('foo', 'Foobar');
$form2 = Form::label('foo', 'Foobar', array('class' => 'control-label'));
$form3 = Form::label('foo', 'Foobar <i>baz</i>', null, false);
$this->assertEquals('<label for="foo">Foobar</label>', $form1);
$this->assertEquals('<label for="foo" class="control-label">Foobar</label>', $form2);
$this->assertEquals('<label for="foo">Foobar <i>baz</i></label>', $form3);
}
/**

View File

@ -28,6 +28,7 @@ public function __construct(TestClassOneForIoC $class_one)
}
}
use \Laravel\IoC as IoC;
class IoCTest extends PHPUnit_Framework_TestCase {
@ -134,7 +135,7 @@ public function testClassTwoForIoCResolves()
public function testClassTwoResolvesClassOneDependency()
{
$test = IoC::resolve('TestClassTwoForIoC');
$this->assertInstanceOf('TestClassOneForIoC', $test->TestClassOneForIoC);
$this->assertInstanceOf('TestClassOneForIoC', $test->class_one);
}
/**
@ -146,8 +147,21 @@ public function testClassTwoResolvesClassOneWithArgument()
$class_one = IoC::resolve('TestClassOneForIoC');
$class_one->test_variable = 42;
$class_two = IoC::resolve('TestClassTwoForIoC', [$class_one]);
$class_two = IoC::resolve('TestClassTwoForIoC', array($class_one));
$this->assertEquals(42, $class_two->class_one->test_variable);
}
public function testCanUnregisterRegistered()
{
$testClass = 'test';
IoC::register($testClass, function() {});
$this->assertTrue(IoC::registered($testClass));
IoC::unregister($testClass);
$this->assertFalse(IoC::registered($testClass));
}
}

View File

@ -0,0 +1,172 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation;
/**
* Represents an Accept-* header.
*
* An accept header is compound with a list of items,
* sorted by descending quality.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class AcceptHeader
{
/**
* @var AcceptHeaderItem[]
*/
private $items = array();
/**
* @var bool
*/
private $sorted = true;
/**
* Constructor.
*
* @param AcceptHeaderItem[] $items
*/
public function __construct(array $items)
{
foreach ($items as $item) {
$this->add($item);
}
}
/**
* Builds an AcceptHeader instance from a string.
*
* @param string $headerValue
*
* @return AcceptHeader
*/
public static function fromString($headerValue)
{
$index = 0;
return new self(array_map(function ($itemValue) use (&$index) {
$item = AcceptHeaderItem::fromString($itemValue);
$item->setIndex($index++);
return $item;
}, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)));
}
/**
* Returns header value's string representation.
*
* @return string
*/
public function __toString()
{
return implode(',', $this->items);
}
/**
* Tests if header has given value.
*
* @param string $value
*
* @return Boolean
*/
public function has($value)
{
return isset($this->items[$value]);
}
/**
* Returns given value's item, if exists.
*
* @param string $value
*
* @return AcceptHeaderItem|null
*/
public function get($value)
{
return isset($this->items[$value]) ? $this->items[$value] : null;
}
/**
* Adds an item.
*
* @param AcceptHeaderItem $item
*
* @return AcceptHeader
*/
public function add(AcceptHeaderItem $item)
{
$this->items[$item->getValue()] = $item;
$this->sorted = false;
return $this;
}
/**
* Returns all items.
*
* @return AcceptHeaderItem[]
*/
public function all()
{
$this->sort();
return $this->items;
}
/**
* Filters items on their value using given regex.
*
* @param string $pattern
*
* @return AcceptHeader
*/
public function filter($pattern)
{
return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) {
return preg_match($pattern, $item->getValue());
}));
}
/**
* Returns first item.
*
* @return AcceptHeaderItem|null
*/
public function first()
{
$this->sort();
return !empty($this->items) ? reset($this->items) : null;
}
/**
* Sorts items by descending quality
*/
private function sort()
{
if (!$this->sorted) {
uasort($this->items, function ($a, $b) {
$qA = $a->getQuality();
$qB = $b->getQuality();
if ($qA === $qB) {
return $a->getIndex() > $b->getIndex() ? 1 : -1;
}
return $qA > $qB ? -1 : 1;
});
$this->sorted = true;
}
}
}

View File

@ -0,0 +1,226 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation;
/**
* Represents an Accept-* header item.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class AcceptHeaderItem
{
/**
* @var string
*/
private $value;
/**
* @var float
*/
private $quality = 1.0;
/**
* @var int
*/
private $index = 0;
/**
* @var array
*/
private $attributes = array();
/**
* Constructor.
*
* @param string $value
* @param array $attributes
*/
public function __construct($value, array $attributes = array())
{
$this->value = $value;
foreach ($attributes as $name => $value) {
$this->setAttribute($name, $value);
}
}
/**
* Builds an AcceptHeaderInstance instance from a string.
*
* @param string $itemValue
*
* @return AcceptHeaderItem
*/
public static function fromString($itemValue)
{
$bits = preg_split('/\s*(?:;*("[^"]+");*|;*(\'[^\']+\');*|;+)\s*/', $itemValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$value = array_shift($bits);
$attributes = array();
$lastNullAttribute = null;
foreach ($bits as $bit) {
if (($start = substr($bit, 0, 1)) === ($end = substr($bit, -1)) && ($start === '"' || $start === '\'')) {
$attributes[$lastNullAttribute] = substr($bit, 1, -1);
} elseif ('=' === $end) {
$lastNullAttribute = $bit = substr($bit, 0, -1);
$attributes[$bit] = null;
} else {
$parts = explode('=', $bit);
$attributes[$parts[0]] = isset($parts[1]) && strlen($parts[1]) > 0 ? $parts[1] : '';
}
}
return new self(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ($start === '"' || $start === '\'') ? substr($value, 1, -1) : $value, $attributes);
}
/**
* Returns header value's string representation.
*
* @return string
*/
public function __toString()
{
$string = $this->value.($this->quality < 1 ? ';q='.$this->quality : '');
if (count($this->attributes) > 0) {
$string .= ';'.implode(';', array_map(function($name, $value) {
return sprintf(preg_match('/[,;=]/', $value) ? '%s="%s"' : '%s=%s', $name, $value);
}, array_keys($this->attributes), $this->attributes));
}
return $string;
}
/**
* Set the item value.
*
* @param string $value
*
* @return AcceptHeaderItem
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* Returns the item value.
*
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Set the item quality.
*
* @param float $quality
*
* @return AcceptHeaderItem
*/
public function setQuality($quality)
{
$this->quality = $quality;
return $this;
}
/**
* Returns the item quality.
*
* @return float
*/
public function getQuality()
{
return $this->quality;
}
/**
* Set the item index.
*
* @param int $index
*
* @return AcceptHeaderItem
*/
public function setIndex($index)
{
$this->index = $index;
return $this;
}
/**
* Returns the item index.
*
* @return int
*/
public function getIndex()
{
return $this->index;
}
/**
* Tests if an attribute exists.
*
* @param string $name
*
* @return Boolean
*/
public function hasAttribute($name)
{
return isset($this->attributes[$name]);
}
/**
* Returns an attribute by its name.
*
* @param string $name
* @param mixed $default
*
* @return mixed
*/
public function getAttribute($name, $default = null)
{
return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
}
/**
* Returns all attributes.
*
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Set an attribute.
*
* @param string $name
* @param string $value
*
* @return AcceptHeaderItem
*/
public function setAttribute($name, $value)
{
if ('q' === $name) {
$this->quality = (float) $value;
} else {
$this->attributes[$name] = (string) $value;
}
return $this;
}
}

View File

@ -0,0 +1,278 @@
<?php
/**
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
/**
* BinaryFileResponse represents an HTTP response delivering a file.
*
* @author Niklas Fiekas <niklas.fiekas@tu-clausthal.de>
* @author stealth35 <stealth35-php@live.fr>
* @author Igor Wiedler <igor@wiedler.ch>
* @author Jordan Alliot <jordan.alliot@gmail.com>
* @author Sergey Linnik <linniksa@gmail.com>
*/
class BinaryFileResponse extends Response
{
protected static $trustXSendfileTypeHeader = false;
protected $file;
protected $offset;
protected $maxlen;
/**
* Constructor.
*
* @param SplFileInfo|string $file The file to stream
* @param integer $status The response status code
* @param array $headers An array of response headers
* @param boolean $public Files are public by default
* @param null|string $contentDisposition The type of Content-Disposition to set automatically with the filename
* @param boolean $autoEtag Whether the ETag header should be automatically set
* @param boolean $autoLastModified Whether the Last-Modified header should be automatically set
*/
public function __construct($file, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
{
parent::__construct(null, $status, $headers);
$this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified);
if ($public) {
$this->setPublic();
}
}
/**
* {@inheritdoc}
*/
public static function create($file = null, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
{
return new static($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified);
}
/**
* Sets the file to stream.
*
* @param SplFileInfo|string $file The file to stream
* @param string $contentDisposition
* @param Boolean $autoEtag
* @param Boolean $autoLastModified
*
* @return BinaryFileResponse
*
* @throws FileException
*/
public function setFile($file, $contentDisposition = null, $autoEtag = false, $autoLastModified = true)
{
$file = new File((string) $file);
if (!$file->isReadable()) {
throw new FileException('File must be readable.');
}
$this->file = $file;
if ($autoEtag) {
$this->setAutoEtag();
}
if ($autoLastModified) {
$this->setAutoLastModified();
}
if ($contentDisposition) {
$this->setContentDisposition($contentDisposition);
}
return $this;
}
/**
* Gets the file.
*
* @return File The file to stream
*/
public function getFile()
{
return $this->file;
}
/**
* Automatically sets the Last-Modified header according the file modification date.
*/
public function setAutoLastModified()
{
$this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime()));
return $this;
}
/**
* Automatically sets the ETag header according to the checksum of the file.
*/
public function setAutoEtag()
{
$this->setEtag(sha1_file($this->file->getPathname()));
return $this;
}
/**
* Sets the Content-Disposition header with the given filename.
*
* @param string $disposition ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT
* @param string $filename Optionally use this filename instead of the real name of the file
* @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename
*
* @return BinaryFileResponse
*/
public function setContentDisposition($disposition, $filename = '', $filenameFallback = '')
{
if ($filename === '') {
$filename = $this->file->getFilename();
}
$dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback);
$this->headers->set('Content-Disposition', $dispositionHeader);
return $this;
}
/**
* {@inheritdoc}
*/
public function prepare(Request $request)
{
$this->headers->set('Content-Length', $this->file->getSize());
$this->headers->set('Accept-Ranges', 'bytes');
$this->headers->set('Content-Transfer-Encoding', 'binary');
if (!$this->headers->has('Content-Type')) {
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
}
if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) {
$this->setProtocolVersion('1.1');
}
$this->offset = 0;
$this->maxlen = -1;
if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) {
// Use X-Sendfile, do not send any content.
$type = $request->headers->get('X-Sendfile-Type');
$path = $this->file->getRealPath();
if (strtolower($type) == 'x-accel-redirect') {
// Do X-Accel-Mapping substitutions.
foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) {
$mapping = explode('=', $mapping, 2);
if (2 == count($mapping)) {
$location = trim($mapping[0]);
$pathPrefix = trim($mapping[1]);
if (substr($path, 0, strlen($pathPrefix)) == $pathPrefix) {
$path = $location . substr($path, strlen($pathPrefix));
break;
}
}
}
}
$this->headers->set($type, $path);
$this->maxlen = 0;
} elseif ($request->headers->has('Range')) {
// Process the range headers.
if (!$request->headers->has('If-Range') || $this->getEtag() == $request->headers->get('If-Range')) {
$range = $request->headers->get('Range');
$fileSize = $this->file->getSize();
list($start, $end) = explode('-', substr($range, 6), 2) + array(0);
$end = ('' === $end) ? $fileSize - 1 : (int) $end;
if ('' === $start) {
$start = $fileSize - $end;
$end = $fileSize - 1;
} else {
$start = (int) $start;
}
$start = max($start, 0);
$end = min($end, $fileSize - 1);
$this->maxlen = $end < $fileSize ? $end - $start + 1 : -1;
$this->offset = $start;
$this->setStatusCode(206);
$this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
}
}
return $this;
}
/**
* Sends the file.
*/
public function sendContent()
{
if (!$this->isSuccessful()) {
parent::sendContent();
return;
}
if (0 === $this->maxlen) {
return;
}
$out = fopen('php://output', 'wb');
$file = fopen($this->file->getPathname(), 'rb');
stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
fclose($out);
fclose($file);
}
/**
* {@inheritdoc}
*
* @throws \LogicException when the content is not null
*/
public function setContent($content)
{
if (null !== $content) {
throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.');
}
}
/**
* {@inheritdoc}
*
* @return false
*/
public function getContent()
{
return false;
}
/**
* Trust X-Sendfile-Type header.
*/
public static function trustXSendfileTypeHeader()
{
self::$trustXSendfileTypeHeader = true;
}
}

View File

@ -1,6 +1,20 @@
CHANGELOG
=========
2.2.0
-----
* fixed the Request::create() precedence (URI information always take precedence now)
* added Request::getTrustedProxies()
* deprecated Request::isProxyTrusted()
* [BC BREAK] JsonResponse does not turn a top level empty array to an object anymore, use an ArrayObject to enforce objects
* added a IpUtils class to check if an IP belongs to a CIDR
* added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method)
* disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to
enable it, and Request::getHttpMethodParameterOverride() to check if it is supported)
* Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3
* Deprecated Flashbag::count() and \Countable interface, will be removed in 2.3
2.1.0
-----

View File

@ -39,6 +39,8 @@ class Cookie
* @param Boolean $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
* @param Boolean $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
*
* @throws \InvalidArgumentException
*
* @api
*/
public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true)

View File

@ -45,7 +45,7 @@ public function __construct($cmd = 'file -b --mime %s 2>/dev/null')
*/
public static function isSupported()
{
return !defined('PHP_WINDOWS_VERSION_BUILD');
return !defined('PHP_WINDOWS_VERSION_BUILD') && function_exists('passthru') && function_exists('escapeshellarg');
}
/**
@ -77,7 +77,7 @@ public function guess($path)
$type = trim(ob_get_clean());
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-]+)#i', $type, $match)) {
if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\.]+)#i', $type, $match)) {
// it's not a type, but an error message
return null;
}

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
@ -99,7 +98,9 @@ public function register(MimeTypeGuesserInterface $guesser)
*
* @return string The mime type or NULL, if none could be guessed
*
* @throws FileException If the file does not exist
* @throws \LogicException
* @throws FileNotFoundException
* @throws AccessDeniedException
*/
public function guess($path)
{

View File

@ -118,6 +118,19 @@ public function getClientOriginalName()
return $this->originalName;
}
/**
* Returns the original file extension
*
* It is extracted from the original file name that was uploaded.
* Then is should not be considered as a safe value.
*
* @return string The extension
*/
public function getClientOriginalExtension()
{
return pathinfo($this->originalName, PATHINFO_EXTENSION);
}
/**
* Returns the file mime type.
*

View File

@ -149,7 +149,7 @@ public function get($key, $default = null, $first = true)
*
* @param string $key The key
* @param string|array $values The value or an array of values
* @param Boolean $replace Whether to replace the actual value of not (true by default)
* @param Boolean $replace Whether to replace the actual value or not (true by default)
*
* @api
*/
@ -223,7 +223,7 @@ public function remove($key)
* @param string $key The parameter key
* @param \DateTime $default The default value
*
* @return null|\DateTime The filtered value
* @return null|\DateTime The parsed DateTime or the default value if the header does not exist
*
* @throws \RuntimeException When the HTTP header is not parseable
*

View File

@ -0,0 +1,111 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation;
/**
* Http utility functions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class IpUtils
{
/**
* This class should not be instantiated
*/
private function __construct() {}
/**
* Validates an IPv4 or IPv6 address.
*
* @param string $requestIp
* @param string $ip
*
* @return boolean Whether the IP is valid
*/
public static function checkIp($requestIp, $ip)
{
if (false !== strpos($requestIp, ':')) {
return self::checkIp6($requestIp, $ip);
}
return self::checkIp4($requestIp, $ip);
}
/**
* Validates an IPv4 address.
*
* @param string $requestIp
* @param string $ip
*
* @return boolean Whether the IP is valid
*/
public static function checkIp4($requestIp, $ip)
{
if (false !== strpos($ip, '/')) {
list($address, $netmask) = explode('/', $ip, 2);
if ($netmask < 1 || $netmask > 32) {
return false;
}
} else {
$address = $ip;
$netmask = 32;
}
return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
}
/**
* Validates an IPv6 address.
*
* @author David Soria Parra <dsp at php dot net>
* @see https://github.com/dsp/v6tools
*
* @param string $requestIp
* @param string $ip
*
* @return boolean Whether the IP is valid
*
* @throws \RuntimeException When IPV6 support is not enabled
*/
public static function checkIp6($requestIp, $ip)
{
if (!((extension_loaded('sockets') && defined('AF_INET6')) || @inet_pton('::1'))) {
throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
}
if (false !== strpos($ip, '/')) {
list($address, $netmask) = explode('/', $ip, 2);
if ($netmask < 1 || $netmask > 128) {
return false;
}
} else {
$address = $ip;
$netmask = 128;
}
$bytesAddr = unpack("n*", inet_pton($address));
$bytesTest = unpack("n*", inet_pton($requestIp));
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
$left = $netmask - 16 * ($i-1);
$left = ($left <= 16) ? $left : 16;
$mask = ~(0xffff >> $left) & 0xffff;
if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
return false;
}
}
return true;
}
}

View File

@ -28,17 +28,20 @@ class JsonResponse extends Response
* @param integer $status The response status code
* @param array $headers An array of response headers
*/
public function __construct($data = array(), $status = 200, $headers = array())
public function __construct($data = null, $status = 200, $headers = array())
{
parent::__construct('', $status, $headers);
if (null === $data) {
$data = new \ArrayObject();
}
$this->setData($data);
}
/**
* {@inheritDoc}
*/
public static function create($data = array(), $status = 200, $headers = array())
public static function create($data = null, $status = 200, $headers = array())
{
return new static($data, $status, $headers);
}
@ -49,6 +52,8 @@ public static function create($data = array(), $status = 200, $headers = array()
* @param string $callback
*
* @return JsonResponse
*
* @throws \InvalidArgumentException
*/
public function setCallback($callback = null)
{
@ -77,11 +82,6 @@ public function setCallback($callback = null)
*/
public function setData($data = array())
{
// root should be JSON object, not array
if (is_array($data) && 0 === count($data)) {
$data = new \ArrayObject();
}
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML.
$this->data = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2012 Fabien Potencier
Copyright (c) 2004-2013 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -96,6 +96,8 @@ public function add(array $parameters = array())
*
* @return mixed
*
* @throws \InvalidArgumentException
*
* @api
*/
public function get($path, $default = null, $deep = false)

View File

@ -31,7 +31,7 @@
Loading
-------
If you are using PHP 5.3.x you must add the following to your autoloader:
If you are not using Composer but are using PHP 5.3.x, you must add the following to your autoloader:
// SessionHandlerInterface
if (!interface_exists('SessionHandlerInterface')) {
@ -43,4 +43,6 @@
You can run the unit tests with the following command:
phpunit
$ cd path/to/Symfony/Component/HttpFoundation/
$ composer.phar install --dev
$ phpunit

View File

@ -29,6 +29,8 @@ class RedirectResponse extends Response
* @param integer $status The status code (302 by default)
* @param array $headers The headers (Location is always set to the given url)
*
* @throws \InvalidArgumentException
*
* @see http://tools.ietf.org/html/rfc2616#section-10.3
*
* @api
@ -72,6 +74,8 @@ public function getTargetUrl()
* @param string $url The URL to redirect to
*
* @return RedirectResponse The current response.
*
* @throws \InvalidArgumentException
*/
public function setTargetUrl($url)
{

View File

@ -30,10 +30,10 @@
*/
class Request
{
const HEADER_CLIENT_IP = 'client_ip';
const HEADER_CLIENT_HOST = 'client_host';
const HEADER_CLIENT_IP = 'client_ip';
const HEADER_CLIENT_HOST = 'client_host';
const HEADER_CLIENT_PROTO = 'client_proto';
const HEADER_CLIENT_PORT = 'client_port';
const HEADER_CLIENT_PORT = 'client_port';
protected static $trustProxy = false;
@ -53,6 +53,8 @@ class Request
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
);
protected static $httpMethodParameterOverride = false;
/**
* @var \Symfony\Component\HttpFoundation\ParameterBag
*
@ -251,6 +253,9 @@ public static function createFromGlobals()
/**
* Creates a Request based on a given URI and configuration.
*
* The information contained in the URI always take precedence
* over the other information (server and parameters).
*
* @param string $uri The URI
* @param string $method The HTTP method
* @param array $parameters The query (GET) or request (POST) parameters
@ -265,7 +270,7 @@ public static function createFromGlobals()
*/
public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
{
$defaults = array(
$server = array_replace(array(
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
'HTTP_HOST' => 'localhost',
@ -278,32 +283,38 @@ public static function create($uri, $method = 'GET', $parameters = array(), $coo
'SCRIPT_FILENAME' => '',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'REQUEST_TIME' => time(),
);
), $server);
$server['PATH_INFO'] = '';
$server['REQUEST_METHOD'] = strtoupper($method);
$components = parse_url($uri);
if (isset($components['host'])) {
$defaults['SERVER_NAME'] = $components['host'];
$defaults['HTTP_HOST'] = $components['host'];
$server['SERVER_NAME'] = $components['host'];
$server['HTTP_HOST'] = $components['host'];
}
if (isset($components['scheme'])) {
if ('https' === $components['scheme']) {
$defaults['HTTPS'] = 'on';
$defaults['SERVER_PORT'] = 443;
$server['HTTPS'] = 'on';
$server['SERVER_PORT'] = 443;
} else {
unset($server['HTTPS']);
$server['SERVER_PORT'] = 80;
}
}
if (isset($components['port'])) {
$defaults['SERVER_PORT'] = $components['port'];
$defaults['HTTP_HOST'] = $defaults['HTTP_HOST'].':'.$components['port'];
$server['SERVER_PORT'] = $components['port'];
$server['HTTP_HOST'] = $server['HTTP_HOST'].':'.$components['port'];
}
if (isset($components['user'])) {
$defaults['PHP_AUTH_USER'] = $components['user'];
$server['PHP_AUTH_USER'] = $components['user'];
}
if (isset($components['pass'])) {
$defaults['PHP_AUTH_PW'] = $components['pass'];
$server['PHP_AUTH_PW'] = $components['pass'];
}
if (!isset($components['path'])) {
@ -314,7 +325,9 @@ public static function create($uri, $method = 'GET', $parameters = array(), $coo
case 'POST':
case 'PUT':
case 'DELETE':
$defaults['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
if (!isset($server['CONTENT_TYPE'])) {
$server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
}
case 'PATCH':
$request = $parameters;
$query = array();
@ -331,14 +344,8 @@ public static function create($uri, $method = 'GET', $parameters = array(), $coo
}
$queryString = http_build_query($query, '', '&');
$uri = $components['path'].('' !== $queryString ? '?'.$queryString : '');
$server = array_replace($defaults, $server, array(
'REQUEST_METHOD' => strtoupper($method),
'PATH_INFO' => '',
'REQUEST_URI' => $uri,
'QUERY_STRING' => $queryString,
));
$server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : '');
$server['QUERY_STRING'] = $queryString;
return new static($query, $request, array(), $cookies, $files, $server, $content);
}
@ -464,6 +471,8 @@ public function overrideGlobals()
*/
public static function trustProxyData()
{
trigger_error('trustProxyData() is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies() instead.', E_USER_DEPRECATED);
self::$trustProxy = true;
}
@ -482,6 +491,16 @@ public static function setTrustedProxies(array $proxies)
self::$trustProxy = $proxies ? true : false;
}
/**
* Gets the list of trusted proxies.
*
* @return array An array of trusted proxies.
*/
public static function getTrustedProxies()
{
return self::$trustedProxies;
}
/**
* Sets the name for trusted headers.
*
@ -496,6 +515,8 @@ public static function setTrustedProxies(array $proxies)
*
* @param string $key The header key
* @param string $value The header name
*
* @throws \InvalidArgumentException
*/
public static function setTrustedHeaderName($key, $value)
{
@ -511,6 +532,8 @@ public static function setTrustedHeaderName($key, $value)
* false otherwise.
*
* @return boolean
*
* @deprecated Deprecated since version 2.2, to be removed in 2.3. Use getTrustedProxies instead.
*/
public static function isProxyTrusted()
{
@ -560,6 +583,29 @@ public static function normalizeQueryString($qs)
return implode('&', $parts);
}
/**
* Enables support for the _method request parameter to determine the intended HTTP method.
*
* Be warned that enabling this feature might lead to CSRF issues in your code.
* Check that you are using CSRF tokens when required.
*
* The HTTP method can only be overridden when the real HTTP method is POST.
*/
public static function enableHttpMethodParameterOverride()
{
self::$httpMethodParameterOverride = true;
}
/**
* Checks whether support for the _method request parameter is enabled.
*
* @return Boolean True when the _method request parameter is enabled, false otherwise
*/
public static function getHttpMethodParameterOverride()
{
return self::$httpMethodParameterOverride;
}
/**
* Gets a "parameter" value.
*
@ -657,8 +703,6 @@ public function setSession(SessionInterface $session)
*
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
*
* @deprecated The proxy argument is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies instead.
*
* @api
*/
public function getClientIp()
@ -703,7 +747,7 @@ public function getScriptName()
*
* * http://localhost/mysite returns an empty string
* * http://localhost/mysite/about returns '/about'
* * htpp://localhost/mysite/enco%20ded returns '/enco%20ded'
* * http://localhost/mysite/enco%20ded returns '/enco%20ded'
* * http://localhost/mysite/about?var=1 returns '/about'
*
* @return string The raw path (i.e. not urldecoded)
@ -897,8 +941,7 @@ public function getSchemeAndHttpHost()
*/
public function getUri()
{
$qs = $this->getQueryString();
if (null !== $qs) {
if (null !== $qs = $this->getQueryString()) {
$qs = '?'.$qs;
}
@ -1017,26 +1060,51 @@ public function setMethod($method)
}
/**
* Gets the request method.
* Gets the request "intended" method.
*
* If the X-HTTP-Method-Override header is set, and if the method is a POST,
* then it is used to determine the "real" intended HTTP method.
*
* The _method request parameter can also be used to determine the HTTP method,
* but only if enableHttpMethodParameterOverride() has been called.
*
* The method is always an uppercased string.
*
* @return string The request method
*
* @api
*
* @see getRealMethod
*/
public function getMethod()
{
if (null === $this->method) {
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
if ('POST' === $this->method) {
$this->method = strtoupper($this->headers->get('X-HTTP-METHOD-OVERRIDE', $this->request->get('_method', $this->query->get('_method', 'POST'))));
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
$this->method = strtoupper($method);
} elseif (self::$httpMethodParameterOverride) {
$this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
}
}
}
return $this->method;
}
/**
* Gets the "real" request method.
*
* @return string The request method
*
* @see getMethod
*/
public function getRealMethod()
{
return strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
}
/**
* Gets the mime type associated with the format.
*
@ -1216,6 +1284,8 @@ public function isMethodSafe()
* @param Boolean $asResource If true, a resource will be returned
*
* @return string|resource The request body content or a resource to read the body stream.
*
* @throws \LogicException
*/
public function getContent($asResource = false)
{
@ -1275,7 +1345,18 @@ public function getPreferredLanguage(array $locales = null)
return $locales[0];
}
$preferredLanguages = array_values(array_intersect($preferredLanguages, $locales));
$extendedPreferredLanguages = array();
foreach ($preferredLanguages as $language) {
$extendedPreferredLanguages[] = $language;
if (false !== $position = strpos($language, '_')) {
$superLanguage = substr($language, 0, $position);
if (!in_array($superLanguage, $preferredLanguages)) {
$extendedPreferredLanguages[] = $superLanguage;
}
}
}
$preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales));
return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0];
}
@ -1293,9 +1374,9 @@ public function getLanguages()
return $this->languages;
}
$languages = $this->splitHttpAcceptHeader($this->headers->get('Accept-Language'));
$languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
$this->languages = array();
foreach ($languages as $lang => $q) {
foreach (array_keys($languages) as $lang) {
if (strstr($lang, '-')) {
$codes = explode('-', $lang);
if ($codes[0] == 'i') {
@ -1335,7 +1416,7 @@ public function getCharsets()
return $this->charsets;
}
return $this->charsets = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept-Charset')));
return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
}
/**
@ -1351,14 +1432,15 @@ public function getAcceptableContentTypes()
return $this->acceptableContentTypes;
}
return $this->acceptableContentTypes = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept')));
return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
}
/**
* Returns true if the request is a XMLHttpRequest.
*
* It works if your JavaScript library set an X-Requested-With HTTP header.
* It is known to work with Prototype, Mootools, jQuery.
* It is known to work with common JavaScript frameworks:
* @link http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript
*
* @return Boolean true if the request is an XMLHttpRequest, false otherwise
*
@ -1375,40 +1457,23 @@ public function isXmlHttpRequest()
* @param string $header Header to split
*
* @return array Array indexed by the values of the Accept-* header in preferred order
*
* @deprecated Deprecated since version 2.2, to be removed in 2.3.
*/
public function splitHttpAcceptHeader($header)
{
if (!$header) {
return array();
}
trigger_error('splitHttpAcceptHeader() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED);
$values = array();
$groups = array();
foreach (array_filter(explode(',', $header)) as $value) {
// Cut off any q-value that might come after a semi-colon
if (preg_match('/;\s*(q=.*$)/', $value, $match)) {
$q = substr(trim($match[1]), 2);
$value = trim(substr($value, 0, -strlen($match[0])));
} else {
$q = 1;
$headers = array();
foreach (AcceptHeader::fromString($header)->all() as $item) {
$key = $item->getValue();
foreach ($item->getAttributes() as $name => $value) {
$key .= sprintf(';%s=%s', $name, $value);
}
$groups[$q][] = $value;
$headers[$key] = $item->getQuality();
}
krsort($groups);
foreach ($groups as $q => $items) {
$q = (float) $q;
if (0 < $q) {
foreach ($items as $value) {
$values[trim($value)] = $q;
}
}
}
return $values;
return $headers;
}
/*
@ -1426,12 +1491,16 @@ protected function prepareRequestUri()
if ($this->headers->has('X_ORIGINAL_URL') && false !== stripos(PHP_OS, 'WIN')) {
// IIS with Microsoft Rewrite Module
$requestUri = $this->headers->get('X_ORIGINAL_URL');
$this->headers->remove('X_ORIGINAL_URL');
} elseif ($this->headers->has('X_REWRITE_URL') && false !== stripos(PHP_OS, 'WIN')) {
// IIS with ISAPI_Rewrite
$requestUri = $this->headers->get('X_REWRITE_URL');
$this->headers->remove('X_REWRITE_URL');
} elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') {
// IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem)
$requestUri = $this->server->get('UNENCODED_URL');
$this->server->remove('UNENCODED_URL');
$this->server->remove('IIS_WasUrlRewritten');
} elseif ($this->server->has('REQUEST_URI')) {
$requestUri = $this->server->get('REQUEST_URI');
// HTTP proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path
@ -1445,8 +1514,12 @@ protected function prepareRequestUri()
if ('' != $this->server->get('QUERY_STRING')) {
$requestUri .= '?'.$this->server->get('QUERY_STRING');
}
$this->server->remove('ORIG_PATH_INFO');
}
// normalize the request URI to ease creating sub-requests from this request
$this->server->set('REQUEST_URI', $requestUri);
return $requestUri;
}

View File

@ -143,95 +143,10 @@ public function matches(Request $request)
return false;
}
if (null !== $this->ip && !$this->checkIp($request->getClientIp(), $this->ip)) {
if (null !== $this->ip && !IpUtils::checkIp($request->getClientIp(), $this->ip)) {
return false;
}
return true;
}
/**
* Validates an IP address.
*
* @param string $requestIp
* @param string $ip
*
* @return boolean True valid, false if not.
*/
protected function checkIp($requestIp, $ip)
{
// IPv6 address
if (false !== strpos($requestIp, ':')) {
return $this->checkIp6($requestIp, $ip);
} else {
return $this->checkIp4($requestIp, $ip);
}
}
/**
* Validates an IPv4 address.
*
* @param string $requestIp
* @param string $ip
*
* @return boolean True valid, false if not.
*/
protected function checkIp4($requestIp, $ip)
{
if (false !== strpos($ip, '/')) {
list($address, $netmask) = explode('/', $ip, 2);
if ($netmask < 1 || $netmask > 32) {
return false;
}
} else {
$address = $ip;
$netmask = 32;
}
return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
}
/**
* Validates an IPv6 address.
*
* @author David Soria Parra <dsp at php dot net>
* @see https://github.com/dsp/v6tools
*
* @param string $requestIp
* @param string $ip
*
* @return boolean True valid, false if not.
*/
protected function checkIp6($requestIp, $ip)
{
if (!((extension_loaded('sockets') && defined('AF_INET6')) || @inet_pton('::1'))) {
throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".');
}
if (false !== strpos($ip, '/')) {
list($address, $netmask) = explode('/', $ip, 2);
if ($netmask < 1 || $netmask > 128) {
return false;
}
} else {
$address = $ip;
$netmask = 128;
}
$bytesAddr = unpack("n*", inet_pton($address));
$bytesTest = unpack("n*", inet_pton($requestIp));
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) {
$left = $netmask - 16 * ($i-1);
$left = ($left <= 16) ? $left : 16;
$mask = ~(0xffff >> $left) & 0xffff;
if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
return false;
}
}
return true;
}
}

View File

@ -131,6 +131,8 @@ class Response
* @param integer $status The response status code
* @param array $headers An array of response headers
*
* @throws \InvalidArgumentException When the HTTP status code is not valid
*
* @api
*/
public function __construct($content = '', $status = 200, $headers = array())
@ -231,7 +233,7 @@ public function prepare(Request $request)
$headers->remove('Content-Length');
}
if ('HEAD' === $request->getMethod()) {
if ($request->isMethod('HEAD')) {
// cf. RFC2616 14.13
$length = $headers->get('Content-Length');
$this->setContent(null);
@ -251,6 +253,16 @@ public function prepare(Request $request)
$this->headers->set('expires', -1);
}
/**
* Check if we need to remove Cache-Control for ssl encrypted downloads when using IE < 9
* @link http://support.microsoft.com/kb/323308
*/
if (false !== stripos($this->headers->get('Content-Disposition'), 'attachment') && preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT'), $match) == 1 && true === $request->isSecure()) {
if (intval(preg_replace("/(MSIE )(.*?);/", "$2", $match[0])) < 9) {
$this->headers->remove('Cache-Control');
}
}
return $this;
}
@ -270,7 +282,7 @@ public function sendHeaders()
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
// headers
foreach ($this->headers->all() as $name => $values) {
foreach ($this->headers->allPreserveCase() as $name => $values) {
foreach ($values as $value) {
header($name.': '.$value, false);
}
@ -336,6 +348,8 @@ public function send()
*
* @return Response
*
* @throws \UnexpectedValueException
*
* @api
*/
public function setContent($content)
@ -431,7 +445,7 @@ public function setStatusCode($code, $text = null)
/**
* Retrieves the status code for the current web response.
*
* @return string Status code
* @return integer Status code
*
* @api
*/
@ -499,7 +513,7 @@ public function isCacheable()
*
* Fresh responses may be served from cache without any interaction with the
* origin. A response is considered fresh when it includes a Cache-Control/max-age
* indicator or Expiration header and the calculated age is less than the freshness lifetime.
* indicator or Expires header and the calculated age is less than the freshness lifetime.
*
* @return Boolean true if the response is fresh, false otherwise
*
@ -612,8 +626,8 @@ public function setDate(\DateTime $date)
*/
public function getAge()
{
if ($age = $this->headers->get('Age')) {
return $age;
if (null !== $age = $this->headers->get('Age')) {
return (int) $age;
}
return max(time() - $this->getDate()->format('U'), 0);
@ -638,21 +652,26 @@ public function expire()
/**
* Returns the value of the Expires header as a DateTime instance.
*
* @return \DateTime A DateTime instance
* @return \DateTime|null A DateTime instance or null if the header does not exist
*
* @api
*/
public function getExpires()
{
return $this->headers->getDate('Expires');
try {
return $this->headers->getDate('Expires');
} catch (\RuntimeException $e) {
// according to RFC 2616 invalid date formats (e.g. "0" and "-1") must be treated as in the past
return \DateTime::createFromFormat(DATE_RFC2822, 'Sat, 01 Jan 00 00:00:00 +0000');
}
}
/**
* Sets the Expires HTTP header with a DateTime instance.
*
* If passed a null value, it removes the header.
* Passing null as value will remove the header.
*
* @param \DateTime $date A \DateTime instance
* @param \DateTime|null $date A \DateTime instance or null to remove the header
*
* @return Response
*
@ -672,7 +691,7 @@ public function setExpires(\DateTime $date = null)
}
/**
* Sets the number of seconds after the time specified in the response's Date
* Returns the number of seconds after the time specified in the response's Date
* header when the the response should no longer be considered fresh.
*
* First, it checks for a s-maxage directive, then a max-age directive, and then it falls
@ -684,12 +703,12 @@ public function setExpires(\DateTime $date = null)
*/
public function getMaxAge()
{
if ($age = $this->headers->getCacheControlDirective('s-maxage')) {
return $age;
if ($this->headers->hasCacheControlDirective('s-maxage')) {
return (int) $this->headers->getCacheControlDirective('s-maxage');
}
if ($age = $this->headers->getCacheControlDirective('max-age')) {
return $age;
if ($this->headers->hasCacheControlDirective('max-age')) {
return (int) $this->headers->getCacheControlDirective('max-age');
}
if (null !== $this->getExpires()) {
@ -750,7 +769,7 @@ public function setSharedMaxAge($value)
*/
public function getTtl()
{
if ($maxAge = $this->getMaxAge()) {
if (null !== $maxAge = $this->getMaxAge()) {
return $maxAge - $this->getAge();
}
@ -796,7 +815,9 @@ public function setClientTtl($seconds)
/**
* Returns the Last-Modified HTTP header as a DateTime instance.
*
* @return \DateTime A DateTime instance
* @return \DateTime|null A DateTime instance or null if the header does not exist
*
* @throws \RuntimeException When the HTTP header is not parseable
*
* @api
*/
@ -808,9 +829,9 @@ public function getLastModified()
/**
* Sets the Last-Modified HTTP header with a DateTime instance.
*
* If passed a null value, it removes the header.
* Passing null as value will remove the header.
*
* @param \DateTime $date A \DateTime instance
* @param \DateTime|null $date A \DateTime instance or null to remove the header
*
* @return Response
*
@ -832,7 +853,7 @@ public function setLastModified(\DateTime $date = null)
/**
* Returns the literal value of the ETag HTTP header.
*
* @return string The ETag HTTP header
* @return string|null The ETag HTTP header or null if it does not exist
*
* @api
*/
@ -844,8 +865,8 @@ public function getEtag()
/**
* Sets the ETag value.
*
* @param string $etag The ETag unique identifier
* @param Boolean $weak Whether you want a weak ETag or not
* @param string|null $etag The ETag unique identifier or null to remove the header
* @param Boolean $weak Whether you want a weak ETag or not
*
* @return Response
*
@ -875,6 +896,8 @@ public function setEtag($etag = null, $weak = false)
*
* @return Response
*
* @throws \InvalidArgumentException
*
* @api
*/
public function setCache(array $options)
@ -952,7 +975,7 @@ public function setNotModified()
*/
public function hasVary()
{
return (Boolean) $this->headers->get('Vary');
return null !== $this->headers->get('Vary');
}
/**
@ -1108,7 +1131,7 @@ public function isOk()
}
/**
* Is the reponse forbidden?
* Is the response forbidden?
*
* @return Boolean
*

View File

@ -36,6 +36,11 @@ class ResponseHeaderBag extends HeaderBag
*/
protected $cookies = array();
/**
* @var array
*/
protected $headerNames = array();
/**
* Constructor.
*
@ -48,7 +53,7 @@ public function __construct(array $headers = array())
parent::__construct($headers);
if (!isset($this->headers['cache-control'])) {
$this->set('cache-control', '');
$this->set('Cache-Control', '');
}
}
@ -62,9 +67,21 @@ public function __toString()
$cookies .= 'Set-Cookie: '.$cookie."\r\n";
}
ksort($this->headerNames);
return parent::__toString().$cookies;
}
/**
* Returns the headers, with original capitalizations.
*
* @return array An array of headers
*/
public function allPreserveCase()
{
return array_combine($this->headerNames, $this->headers);
}
/**
* {@inheritdoc}
*
@ -72,10 +89,12 @@ public function __toString()
*/
public function replace(array $headers = array())
{
$this->headerNames = array();
parent::replace($headers);
if (!isset($this->headers['cache-control'])) {
$this->set('cache-control', '');
$this->set('Cache-Control', '');
}
}
@ -88,10 +107,14 @@ public function set($key, $values, $replace = true)
{
parent::set($key, $values, $replace);
$uniqueKey = strtr(strtolower($key), '_', '-');
$this->headerNames[$uniqueKey] = $key;
// ensure the cache-control header has sensible defaults
if (in_array(strtr(strtolower($key), '_', '-'), array('cache-control', 'etag', 'last-modified', 'expires'))) {
if (in_array($uniqueKey, array('cache-control', 'etag', 'last-modified', 'expires'))) {
$computed = $this->computeCacheControlValue();
$this->headers['cache-control'] = array($computed);
$this->headerNames['cache-control'] = 'Cache-Control';
$this->computedCacheControl = $this->parseCacheControl($computed);
}
}
@ -105,7 +128,10 @@ public function remove($key)
{
parent::remove($key);
if ('cache-control' === strtr(strtolower($key), '_', '-')) {
$uniqueKey = strtr(strtolower($key), '_', '-');
unset($this->headerNames[$uniqueKey]);
if ('cache-control' === $uniqueKey) {
$this->computedCacheControl = array();
}
}

View File

@ -31,7 +31,7 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta
/**
* Constructor.
*
* @param string $storageKey The key used to store flashes in the session.
* @param string $storageKey The key used to store attributes in the session.
*/
public function __construct($storageKey = '_sf2_attributes')
{

View File

@ -177,10 +177,17 @@ public function getIterator()
/**
* Returns the number of flashes.
*
* This method does not work.
*
* @deprecated in 2.2, removed in 2.3
* @see https://github.com/symfony/symfony/issues/6408
*
* @return int The number of flashes
*/
public function count()
{
trigger_error(sprintf('%s() is deprecated since 2.2 and will be removed in 2.3', __METHOD__), E_USER_DEPRECATED);
return count($this->flashes);
}
}

View File

@ -259,6 +259,8 @@ public function getFlashBag()
*/
public function getFlashes()
{
trigger_error('getFlashes() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
$all = $this->getBag($this->flashName)->all();
$return = array();
@ -282,6 +284,8 @@ public function getFlashes()
*/
public function setFlashes($values)
{
trigger_error('setFlashes() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
foreach ($values as $name => $value) {
$this->getBag($this->flashName)->set($name, $value);
}
@ -297,6 +301,8 @@ public function setFlashes($values)
*/
public function getFlash($name, $default = null)
{
trigger_error('getFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
$return = $this->getBag($this->flashName)->get($name);
return empty($return) ? $default : reset($return);
@ -310,6 +316,8 @@ public function getFlash($name, $default = null)
*/
public function setFlash($name, $value)
{
trigger_error('setFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
$this->getBag($this->flashName)->set($name, $value);
}
@ -322,6 +330,8 @@ public function setFlash($name, $value)
*/
public function hasFlash($name)
{
trigger_error('hasFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
return $this->getBag($this->flashName)->has($name);
}
@ -332,6 +342,8 @@ public function hasFlash($name)
*/
public function removeFlash($name)
{
trigger_error('removeFlash() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
$this->getBag($this->flashName)->get($name);
}
@ -342,6 +354,8 @@ public function removeFlash($name)
*/
public function clearFlashes()
{
trigger_error('clearFlashes() is deprecated since version 2.1 and will be removed in 2.3. Use the FlashBag instead.', E_USER_DEPRECATED);
return $this->getBag($this->flashName)->clear();
}
}

View File

@ -36,6 +36,13 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
/**
* Constructor.
*
* List of available options:
* * database: The name of the database [required]
* * collection: The name of the collection [required]
* * id_field: The field name for storing the session id [default: _id]
* * data_field: The field name for storing the session data [default: data]
* * time_field: The field name for storing the timestamp [default: time]
*
* @param \Mongo|\MongoClient $mongo A MongoClient or Mongo instance
* @param array $options An associative array of field options
*
@ -55,9 +62,9 @@ public function __construct($mongo, array $options)
$this->mongo = $mongo;
$this->options = array_merge(array(
'id_field' => 'sess_id',
'data_field' => 'sess_data',
'time_field' => 'sess_time',
'id_field' => '_id',
'data_field' => 'data',
'time_field' => 'time',
), $options);
}
@ -82,10 +89,9 @@ public function close()
*/
public function destroy($sessionId)
{
$this->getCollection()->remove(
array($this->options['id_field'] => $sessionId),
array('justOne' => true)
);
$this->getCollection()->remove(array(
$this->options['id_field'] => $sessionId
));
return true;
}
@ -95,11 +101,21 @@ public function destroy($sessionId)
*/
public function gc($lifetime)
{
$time = new \MongoTimestamp(time() - $lifetime);
/* Note: MongoDB 2.2+ supports TTL collections, which may be used in
* place of this method by indexing the "time_field" field with an
* "expireAfterSeconds" option. Regardless of whether TTL collections
* are used, consider indexing this field to make the remove query more
* efficient.
*
* See: http://docs.mongodb.org/manual/tutorial/expire-data/
*/
$time = new \MongoDate(time() - $lifetime);
$this->getCollection()->remove(array(
$this->options['time_field'] => array('$lt' => $time),
));
return true;
}
/**
@ -107,16 +123,13 @@ public function gc($lifetime)
*/
public function write($sessionId, $data)
{
$data = array(
$this->options['id_field'] => $sessionId,
$this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY),
$this->options['time_field'] => new \MongoTimestamp()
);
$this->getCollection()->update(
array($this->options['id_field'] => $sessionId),
array('$set' => $data),
array('upsert' => true)
array('$set' => array(
$this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY),
$this->options['time_field'] => new \MongoDate(),
)),
array('upsert' => true, 'multiple' => false)
);
return true;

View File

@ -27,17 +27,17 @@ class NativeSessionStorage implements SessionStorageInterface
/**
* Array of SessionBagInterface
*
* @var array
* @var SessionBagInterface[]
*/
protected $bags;
/**
* @var boolean
* @var Boolean
*/
protected $started = false;
/**
* @var boolean
* @var Boolean
*/
protected $closed = false;
@ -332,9 +332,9 @@ public function setOptions(array $options)
* Registers save handler as a PHP session handler.
*
* To use internal PHP session save handlers, override this method using ini_set with
* session.save_handlers and session.save_path e.g.
* session.save_handler and session.save_path e.g.
*
* ini_set('session.save_handlers', 'files');
* ini_set('session.save_handler', 'files');
* ini_set('session.save_path', /tmp');
*
* @see http://php.net/session-set-save-handler

View File

@ -99,6 +99,8 @@ public function getId()
* Sets the session ID.
*
* @param string $id
*
* @throws \LogicException
*/
public function setId($id)
{
@ -123,6 +125,8 @@ public function getName()
* Sets the session name.
*
* @param string $name
*
* @throws \LogicException
*/
public function setName($name)
{

View File

@ -62,6 +62,8 @@ public static function create($callback = null, $status = 200, $headers = array(
* Sets the PHP callback associated with this Response.
*
* @param mixed $callback A valid PHP callback
*
* @throws \LogicException
*/
public function setCallback($callback)
{

View File

@ -19,11 +19,14 @@
"php": ">=5.3.3"
},
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpFoundation": "",
"SessionHandlerInterface": "Symfony/Component/HttpFoundation/Resources/stubs"
}
"psr-0": { "Symfony\\Component\\HttpFoundation\\": "" },
"classmap": [ "Symfony/Component/HttpFoundation/Resources/stubs" ]
},
"target-dir": "Symfony/Component/HttpFoundation",
"minimum-stability": "dev"
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
}
}

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="Symfony HttpFoundation Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Resources</directory>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -3,7 +3,7 @@
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @version 3.2.13
* @version 3.2.14
* @author Taylor Otwell <taylorotwell@gmail.com>
* @link http://laravel.com
*/

View File

@ -3,7 +3,7 @@
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @version 3.2.13
* @version 3.2.14
* @author Taylor Otwell <taylorotwell@gmail.com>
* @link http://laravel.com
*/

View File

@ -1,5 +1,4 @@
@import url(http://fonts.googleapis.com/css?family=Ubuntu);
@import url(http://fonts.googleapis.com/css?family=Droid+Sans);
@import url(http://fonts.googleapis.com/css?family=Ubuntu|Droid+Sans);
article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; }
audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; }