Merge branch '2.4'
* 2.4: Little correction for case 'ar' No need to use mb functions here Fix doc-blocks Fix doc blocks [HttpFoundation] update phpdoc of SessionHandlerInterface and unify parameters of all handlers according to interface [Doctrine Bridge] fix DbalSessionHandler for high concurrency, interface compliance, compatibility with all drivers (oci8, mysqli, pdo with mysql, sqlsrv, sqlite) [Finder] Marked test skipped when ftp stream wrapper is not available Conflicts: src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
This commit is contained in:
commit
02fdbb25ad
@ -11,37 +11,64 @@
|
|||||||
|
|
||||||
namespace Symfony\Bridge\Doctrine\HttpFoundation;
|
namespace Symfony\Bridge\Doctrine\HttpFoundation;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Connection;
|
||||||
|
use Doctrine\DBAL\Driver\Connection as DriverConnection;
|
||||||
|
use Doctrine\DBAL\Driver\Mysqli\MysqliConnection;
|
||||||
|
use Doctrine\DBAL\Driver\OCI8\OCI8Connection;
|
||||||
|
use Doctrine\DBAL\Driver\PDOConnection;
|
||||||
|
use Doctrine\DBAL\Driver\SQLSrv\SQLSrvConnection;
|
||||||
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
||||||
use Doctrine\DBAL\Driver\Connection;
|
use Doctrine\DBAL\Platforms\OraclePlatform;
|
||||||
|
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||||
|
use Doctrine\DBAL\Platforms\SQLServerPlatform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DBAL based session storage.
|
* DBAL based session storage.
|
||||||
*
|
*
|
||||||
|
* This implementation is very similar to Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
|
||||||
|
* but uses the Doctrine driver connection interface and thus also works with non-PDO-based drivers like mysqli and OCI8.
|
||||||
|
*
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||||
|
* @author Tobias Schultze <http://tobion.de>
|
||||||
*/
|
*/
|
||||||
class DbalSessionHandler implements \SessionHandlerInterface
|
class DbalSessionHandler implements \SessionHandlerInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var Connection
|
* @var DriverConnection
|
||||||
*/
|
*/
|
||||||
private $con;
|
private $con;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $tableName;
|
private $table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Column for session id
|
||||||
|
*/
|
||||||
|
private $idCol = 'sess_id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Column for session data
|
||||||
|
*/
|
||||||
|
private $dataCol = 'sess_data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string Column for timestamp
|
||||||
|
*/
|
||||||
|
private $timeCol = 'sess_time';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param Connection $con An instance of Connection.
|
* @param DriverConnection $con A driver connection, preferably a wrapper Doctrine\DBAL\Connection for lazy connections
|
||||||
* @param string $tableName Table name.
|
* @param string $tableName Table name
|
||||||
*/
|
*/
|
||||||
public function __construct(Connection $con, $tableName = 'sessions')
|
public function __construct(DriverConnection $con, $tableName = 'sessions')
|
||||||
{
|
{
|
||||||
$this->con = $con;
|
$this->con = $con;
|
||||||
$this->tableName = $tableName;
|
$this->table = $tableName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,7 +84,6 @@ class DbalSessionHandler implements \SessionHandlerInterface
|
|||||||
*/
|
*/
|
||||||
public function close()
|
public function close()
|
||||||
{
|
{
|
||||||
// do nothing
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,12 +92,15 @@ class DbalSessionHandler implements \SessionHandlerInterface
|
|||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
|
// delete the record associated with this id
|
||||||
|
$sql = "DELETE FROM $this->table WHERE $this->idCol = :id";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_id = :id", array(
|
$stmt = $this->con->prepare($sql);
|
||||||
'id' => $id,
|
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
||||||
));
|
$stmt->execute();
|
||||||
} catch (\PDOException $e) {
|
} catch (\Exception $e) {
|
||||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
|
throw new \RuntimeException(sprintf('Exception was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -82,12 +111,15 @@ class DbalSessionHandler implements \SessionHandlerInterface
|
|||||||
*/
|
*/
|
||||||
public function gc($lifetime)
|
public function gc($lifetime)
|
||||||
{
|
{
|
||||||
|
// delete the session records that have expired
|
||||||
|
$sql = "DELETE FROM $this->table WHERE $this->timeCol < :time";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_time < :time", array(
|
$stmt = $this->con->prepare($sql);
|
||||||
'time' => time() - $lifetime,
|
$stmt->bindValue(':time', time() - $lifetime, \PDO::PARAM_INT);
|
||||||
));
|
$stmt->execute();
|
||||||
} catch (\PDOException $e) {
|
} catch (\Exception $e) {
|
||||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
|
throw new \RuntimeException(sprintf('Exception was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -98,21 +130,23 @@ class DbalSessionHandler implements \SessionHandlerInterface
|
|||||||
*/
|
*/
|
||||||
public function read($id)
|
public function read($id)
|
||||||
{
|
{
|
||||||
try {
|
$sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id";
|
||||||
$data = $this->con->executeQuery("SELECT sess_data FROM {$this->tableName} WHERE sess_id = :id", array(
|
|
||||||
'id' => $id,
|
|
||||||
))->fetchColumn();
|
|
||||||
|
|
||||||
if (false !== $data) {
|
try {
|
||||||
return base64_decode($data);
|
$stmt = $this->con->prepare($sql);
|
||||||
|
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
// We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed
|
||||||
|
$sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM);
|
||||||
|
|
||||||
|
if ($sessionRows) {
|
||||||
|
return base64_decode($sessionRows[0][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// session does not exist, create it
|
|
||||||
$this->createNewSession($id);
|
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
} catch (\PDOException $e) {
|
} catch (\Exception $e) {
|
||||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e);
|
throw new \RuntimeException(sprintf('Exception was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,54 +155,88 @@ class DbalSessionHandler implements \SessionHandlerInterface
|
|||||||
*/
|
*/
|
||||||
public function write($id, $data)
|
public function write($id, $data)
|
||||||
{
|
{
|
||||||
$platform = $this->con->getDatabasePlatform();
|
// Session data can contain non binary safe characters so we need to encode it.
|
||||||
|
$encoded = base64_encode($data);
|
||||||
|
|
||||||
// this should maybe be abstracted in Doctrine DBAL
|
// We use a MERGE SQL query when supported by the database.
|
||||||
if ($platform instanceof MySqlPlatform) {
|
// Otherwise we have to use a transactional DELETE followed by INSERT to prevent duplicate entries under high concurrency.
|
||||||
$sql = "INSERT INTO {$this->tableName} (sess_id, sess_data, sess_time) VALUES (%1\$s, %2\$s, %3\$d) "
|
|
||||||
."ON DUPLICATE KEY UPDATE sess_data = VALUES(sess_data), sess_time = CASE WHEN sess_time = %3\$d THEN (VALUES(sess_time) + 1) ELSE VALUES(sess_time) END";
|
|
||||||
} else {
|
|
||||||
$sql = "UPDATE {$this->tableName} SET sess_data = %2\$s, sess_time = %3\$d WHERE sess_id = %1\$s";
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$rowCount = $this->con->exec(sprintf(
|
$mergeSql = $this->getMergeSql();
|
||||||
$sql,
|
|
||||||
$this->con->quote($id),
|
|
||||||
//session data can contain non binary safe characters so we need to encode it
|
|
||||||
$this->con->quote(base64_encode($data)),
|
|
||||||
time()
|
|
||||||
));
|
|
||||||
|
|
||||||
if (!$rowCount) {
|
if (null !== $mergeSql) {
|
||||||
// No session exists in the database to update. This happens when we have called
|
$mergeStmt = $this->con->prepare($mergeSql);
|
||||||
// session_regenerate_id()
|
$mergeStmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
||||||
$this->createNewSession($id, $data);
|
$mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
||||||
|
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
|
$mergeStmt->execute();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} catch (\PDOException $e) {
|
|
||||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
|
$this->con->beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$deleteStmt = $this->con->prepare(
|
||||||
|
"DELETE FROM $this->table WHERE $this->idCol = :id"
|
||||||
|
);
|
||||||
|
$deleteStmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
||||||
|
$deleteStmt->execute();
|
||||||
|
|
||||||
|
$insertStmt = $this->con->prepare(
|
||||||
|
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"
|
||||||
|
);
|
||||||
|
$insertStmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
||||||
|
$insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
||||||
|
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
|
$insertStmt->execute();
|
||||||
|
|
||||||
|
$this->con->commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->con->rollback();
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
throw new \RuntimeException(sprintf('Exception was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new session with the given $id and $data
|
* Returns a merge/upsert (i.e. insert or update) SQL query when supported by the database.
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @return string|null The SQL string or null when not supported
|
||||||
* @param string $data
|
*/
|
||||||
*
|
private function getMergeSql()
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function createNewSession($id, $data = '')
|
|
||||||
{
|
{
|
||||||
$this->con->exec(sprintf("INSERT INTO {$this->tableName} (sess_id, sess_data, sess_time) VALUES (%s, %s, %d)",
|
$platform = $pdoDriver = null;
|
||||||
$this->con->quote($id),
|
|
||||||
//session data can contain non binary safe characters so we need to encode it
|
|
||||||
$this->con->quote(base64_encode($data)),
|
|
||||||
time()
|
|
||||||
));
|
|
||||||
|
|
||||||
return true;
|
if ($this->con instanceof Connection) {
|
||||||
|
$platform = $this->con->getDatabasePlatform();
|
||||||
|
} elseif ($this->con instanceof PDOConnection) {
|
||||||
|
$pdoDriver = $this->con->getAttribute(\PDO::ATTR_DRIVER_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case $this->con instanceof MysqliConnection || $platform instanceof MySqlPlatform || 'mysql' === $pdoDriver:
|
||||||
|
return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " .
|
||||||
|
"ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->timeCol = VALUES($this->timeCol)";
|
||||||
|
case $this->con instanceof OCI8Connection || $platform instanceof OraclePlatform || 'oci' === $pdoDriver:
|
||||||
|
// DUAL is Oracle specific dummy table
|
||||||
|
return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) " .
|
||||||
|
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " .
|
||||||
|
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data";
|
||||||
|
case $this->con instanceof SQLSrvConnection || $platform instanceof SQLServerPlatform || 'sqlsrv' === $pdoDriver:
|
||||||
|
// MS SQL Server requires MERGE be terminated by semicolon
|
||||||
|
return "MERGE INTO $this->table USING (SELECT 'x' AS dummy) AS src ON ($this->idCol = :id) " .
|
||||||
|
"WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) " .
|
||||||
|
"WHEN MATCHED THEN UPDATE SET $this->dataCol = :data;";
|
||||||
|
case $platform instanceof SqlitePlatform || 'sqlite' === $pdoDriver:
|
||||||
|
return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,16 +105,8 @@ class WebDebugToolbarListener implements EventSubscriberInterface
|
|||||||
*/
|
*/
|
||||||
protected function injectToolbar(Response $response)
|
protected function injectToolbar(Response $response)
|
||||||
{
|
{
|
||||||
if (function_exists('mb_stripos')) {
|
|
||||||
$posrFunction = 'mb_strripos';
|
|
||||||
$substrFunction = 'mb_substr';
|
|
||||||
} else {
|
|
||||||
$posrFunction = 'strripos';
|
|
||||||
$substrFunction = 'substr';
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = $response->getContent();
|
$content = $response->getContent();
|
||||||
$pos = $posrFunction($content, '</body>');
|
$pos = strripos($content, '</body>');
|
||||||
|
|
||||||
if (false !== $pos) {
|
if (false !== $pos) {
|
||||||
$toolbar = "\n".str_replace("\n", '', $this->twig->render(
|
$toolbar = "\n".str_replace("\n", '', $this->twig->render(
|
||||||
@ -124,7 +116,7 @@ class WebDebugToolbarListener implements EventSubscriberInterface
|
|||||||
'token' => $response->headers->get('X-Debug-Token'),
|
'token' => $response->headers->get('X-Debug-Token'),
|
||||||
)
|
)
|
||||||
))."\n";
|
))."\n";
|
||||||
$content = $substrFunction($content, 0, $pos).$toolbar.$substrFunction($content, $pos);
|
$content = substr($content, 0, $pos).$toolbar.substr($content, $pos);
|
||||||
$response->setContent($content);
|
$response->setContent($content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -835,6 +835,10 @@ class FinderTest extends Iterator\RealIteratorTestCase
|
|||||||
|
|
||||||
public function testNonSeekableStream()
|
public function testNonSeekableStream()
|
||||||
{
|
{
|
||||||
|
if (!in_array('ftp', stream_get_wrappers())) {
|
||||||
|
$this->markTestSkipped(sprintf('Unavailable stream "%s".', 'ftp'));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$i = Finder::create()->in('ftp://ftp.mozilla.org/')->depth(0)->getIterator();
|
$i = Finder::create()->in('ftp://ftp.mozilla.org/')->depth(0)->getIterator();
|
||||||
} catch (\UnexpectedValueException $e) {
|
} catch (\UnexpectedValueException $e) {
|
||||||
|
@ -10,9 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SessionHandlerInterface
|
* SessionHandlerInterface for PHP < 5.4
|
||||||
*
|
|
||||||
* Provides forward compatibility with PHP 5.4
|
|
||||||
*
|
*
|
||||||
* Extensive documentation can be found at php.net, see links:
|
* Extensive documentation can be found at php.net, see links:
|
||||||
*
|
*
|
||||||
@ -25,76 +23,68 @@
|
|||||||
interface SessionHandlerInterface
|
interface SessionHandlerInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Open session.
|
* Re-initializes existing session, or creates a new one.
|
||||||
*
|
*
|
||||||
* @see http://php.net/sessionhandlerinterface.open
|
* @see http://php.net/sessionhandlerinterface.open
|
||||||
*
|
*
|
||||||
* @param string $savePath Save path.
|
* @param string $savePath Save path
|
||||||
* @param string $sessionName Session Name.
|
* @param string $sessionName Session name, see http://php.net/function.session-name.php
|
||||||
*
|
*
|
||||||
* @throws \RuntimeException If something goes wrong starting the session.
|
* @return bool true on success, false on failure
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function open($savePath, $sessionName);
|
public function open($savePath, $sessionName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close session.
|
* Closes the current session.
|
||||||
*
|
*
|
||||||
* @see http://php.net/sessionhandlerinterface.close
|
* @see http://php.net/sessionhandlerinterface.close
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool true on success, false on failure
|
||||||
*/
|
*/
|
||||||
public function close();
|
public function close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read session.
|
* Reads the session data.
|
||||||
*
|
|
||||||
* @param string $sessionId
|
|
||||||
*
|
*
|
||||||
* @see http://php.net/sessionhandlerinterface.read
|
* @see http://php.net/sessionhandlerinterface.read
|
||||||
*
|
*
|
||||||
* @throws \RuntimeException On fatal error but not "record not found".
|
* @param string $sessionId Session ID, see http://php.net/function.session-id
|
||||||
*
|
*
|
||||||
* @return string String as stored in persistent storage or empty string in all other cases.
|
* @return string Same session data as passed in write() or empty string when non-existent or on failure
|
||||||
*/
|
*/
|
||||||
public function read($sessionId);
|
public function read($sessionId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit session to storage.
|
* Writes the session data to the storage.
|
||||||
*
|
*
|
||||||
* @see http://php.net/sessionhandlerinterface.write
|
* @see http://php.net/sessionhandlerinterface.write
|
||||||
*
|
*
|
||||||
* @param string $sessionId Session ID.
|
* @param string $sessionId Session ID , see http://php.net/function.session-id
|
||||||
* @param string $data Session serialized data to save.
|
* @param string $data Serialized session data to save
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool true on success, false on failure
|
||||||
*/
|
*/
|
||||||
public function write($sessionId, $data);
|
public function write($sessionId, $data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys this session.
|
* Destroys a session.
|
||||||
*
|
*
|
||||||
* @see http://php.net/sessionhandlerinterface.destroy
|
* @see http://php.net/sessionhandlerinterface.destroy
|
||||||
*
|
*
|
||||||
* @param string $sessionId Session ID.
|
* @param string $sessionId Session ID, see http://php.net/function.session-id
|
||||||
*
|
*
|
||||||
* @throws \RuntimeException On fatal error.
|
* @return bool true on success, false on failure
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function destroy($sessionId);
|
public function destroy($sessionId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Garbage collection for storage.
|
* Cleans up expired sessions (garbage collection).
|
||||||
*
|
*
|
||||||
* @see http://php.net/sessionhandlerinterface.gc
|
* @see http://php.net/sessionhandlerinterface.gc
|
||||||
*
|
*
|
||||||
* @param int $lifetime Max lifetime in seconds to keep sessions stored.
|
* @param string|int $maxlifetime Sessions that have not updated for the last maxlifetime seconds will be removed
|
||||||
*
|
*
|
||||||
* @throws \RuntimeException On fatal error.
|
* @return bool true on success, false on failure
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function gc($lifetime);
|
public function gc($maxlifetime);
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ class MemcacheSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function gc($lifetime)
|
public function gc($maxlifetime)
|
||||||
{
|
{
|
||||||
// not required here because memcache will auto expire the records anyhow.
|
// not required here because memcache will auto expire the records anyhow.
|
||||||
return true;
|
return true;
|
||||||
|
@ -107,7 +107,7 @@ class MemcachedSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function gc($lifetime)
|
public function gc($maxlifetime)
|
||||||
{
|
{
|
||||||
// not required here because memcached will auto expire the records anyhow.
|
// not required here because memcached will auto expire the records anyhow.
|
||||||
return true;
|
return true;
|
||||||
|
@ -99,7 +99,7 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function gc($lifetime)
|
public function gc($maxlifetime)
|
||||||
{
|
{
|
||||||
/* Note: MongoDB 2.2+ supports TTL collections, which may be used in
|
/* Note: MongoDB 2.2+ supports TTL collections, which may be used in
|
||||||
* place of this method by indexing the "time_field" field with an
|
* place of this method by indexing the "time_field" field with an
|
||||||
@ -109,7 +109,7 @@ class MongoDbSessionHandler implements \SessionHandlerInterface
|
|||||||
*
|
*
|
||||||
* See: http://docs.mongodb.org/manual/tutorial/expire-data/
|
* See: http://docs.mongodb.org/manual/tutorial/expire-data/
|
||||||
*/
|
*/
|
||||||
$time = new \MongoDate(time() - $lifetime);
|
$time = new \MongoDate(time() - $maxlifetime);
|
||||||
|
|
||||||
$this->getCollection()->remove(array(
|
$this->getCollection()->remove(array(
|
||||||
$this->options['time_field'] => array('$lt' => $time),
|
$this->options['time_field'] => array('$lt' => $time),
|
||||||
|
@ -65,7 +65,7 @@ class NullSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function gc($lifetime)
|
public function gc($maxlifetime)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function open($path, $name)
|
public function open($savePath, $sessionName)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -99,14 +99,14 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($sessionId)
|
||||||
{
|
{
|
||||||
// delete the record associated with this id
|
// delete the record associated with this id
|
||||||
$sql = "DELETE FROM $this->table WHERE $this->idCol = :id";
|
$sql = "DELETE FROM $this->table WHERE $this->idCol = :id";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $this->pdo->prepare($sql);
|
$stmt = $this->pdo->prepare($sql);
|
||||||
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e);
|
throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete a session: %s', $e->getMessage()), 0, $e);
|
||||||
@ -118,14 +118,14 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function gc($lifetime)
|
public function gc($maxlifetime)
|
||||||
{
|
{
|
||||||
// delete the session records that have expired
|
// delete the session records that have expired
|
||||||
$sql = "DELETE FROM $this->table WHERE $this->timeCol < :time";
|
$sql = "DELETE FROM $this->table WHERE $this->timeCol < :time";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $this->pdo->prepare($sql);
|
$stmt = $this->pdo->prepare($sql);
|
||||||
$stmt->bindValue(':time', time() - $lifetime, \PDO::PARAM_INT);
|
$stmt->bindValue(':time', time() - $maxlifetime, \PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e);
|
throw new \RuntimeException(sprintf('PDOException was thrown when trying to delete expired sessions: %s', $e->getMessage()), 0, $e);
|
||||||
@ -137,13 +137,13 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function read($id)
|
public function read($sessionId)
|
||||||
{
|
{
|
||||||
$sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id";
|
$sql = "SELECT $this->dataCol FROM $this->table WHERE $this->idCol = :id";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt = $this->pdo->prepare($sql);
|
$stmt = $this->pdo->prepare($sql);
|
||||||
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
$stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
// We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed
|
// We use fetchAll instead of fetchColumn to make sure the DB cursor gets closed
|
||||||
@ -162,7 +162,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function write($id, $data)
|
public function write($sessionId, $data)
|
||||||
{
|
{
|
||||||
// Session data can contain non binary safe characters so we need to encode it.
|
// Session data can contain non binary safe characters so we need to encode it.
|
||||||
$encoded = base64_encode($data);
|
$encoded = base64_encode($data);
|
||||||
@ -175,7 +175,7 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
|
|
||||||
if (null !== $mergeSql) {
|
if (null !== $mergeSql) {
|
||||||
$mergeStmt = $this->pdo->prepare($mergeSql);
|
$mergeStmt = $this->pdo->prepare($mergeSql);
|
||||||
$mergeStmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
$mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||||
$mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
$mergeStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
||||||
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
$mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
$mergeStmt->execute();
|
$mergeStmt->execute();
|
||||||
@ -189,13 +189,13 @@ class PdoSessionHandler implements \SessionHandlerInterface
|
|||||||
$deleteStmt = $this->pdo->prepare(
|
$deleteStmt = $this->pdo->prepare(
|
||||||
"DELETE FROM $this->table WHERE $this->idCol = :id"
|
"DELETE FROM $this->table WHERE $this->idCol = :id"
|
||||||
);
|
);
|
||||||
$deleteStmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
$deleteStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||||
$deleteStmt->execute();
|
$deleteStmt->execute();
|
||||||
|
|
||||||
$insertStmt = $this->pdo->prepare(
|
$insertStmt = $this->pdo->prepare(
|
||||||
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"
|
"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"
|
||||||
);
|
);
|
||||||
$insertStmt->bindParam(':id', $id, \PDO::PARAM_STR);
|
$insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
|
||||||
$insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
$insertStmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
|
||||||
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
$insertStmt->bindValue(':time', time(), \PDO::PARAM_INT);
|
||||||
$insertStmt->execute();
|
$insertStmt->execute();
|
||||||
|
@ -64,25 +64,25 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function read($id)
|
public function read($sessionId)
|
||||||
{
|
{
|
||||||
return (string) $this->handler->read($id);
|
return (string) $this->handler->read($sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function write($id, $data)
|
public function write($sessionId, $data)
|
||||||
{
|
{
|
||||||
return (bool) $this->handler->write($id, $data);
|
return (bool) $this->handler->write($sessionId, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($sessionId)
|
||||||
{
|
{
|
||||||
return (bool) $this->handler->destroy($id);
|
return (bool) $this->handler->destroy($sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage;
|
namespace Symfony\Component\HttpFoundation\Tests\Session\Storage;
|
||||||
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
|
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
|
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy;
|
||||||
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
|
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
|
||||||
|
|
||||||
@ -175,9 +176,9 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
|
||||||
$storage->setSaveHandler(new NativeSessionHandler());
|
$storage->setSaveHandler(new NativeSessionHandler());
|
||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
|
||||||
$storage->setSaveHandler(new SessionHandlerProxy(new SessionHandler()));
|
$storage->setSaveHandler(new SessionHandlerProxy(new NullSessionHandler()));
|
||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
||||||
$storage->setSaveHandler(new SessionHandler());
|
$storage->setSaveHandler(new NullSessionHandler());
|
||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
||||||
$storage->setSaveHandler(new NativeProxy());
|
$storage->setSaveHandler(new NativeProxy());
|
||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy', $storage->getSaveHandler());
|
||||||
@ -199,9 +200,9 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
||||||
$storage->setSaveHandler(new NativeSessionHandler());
|
$storage->setSaveHandler(new NativeSessionHandler());
|
||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
||||||
$storage->setSaveHandler(new SessionHandlerProxy(new SessionHandler()));
|
$storage->setSaveHandler(new SessionHandlerProxy(new NullSessionHandler()));
|
||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
||||||
$storage->setSaveHandler(new SessionHandler());
|
$storage->setSaveHandler(new NullSessionHandler());
|
||||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,30 +255,3 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase
|
|||||||
$storage->start();
|
$storage->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SessionHandler implements \SessionHandlerInterface
|
|
||||||
{
|
|
||||||
public function open($savePath, $sessionName)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function read($id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function write($id, $data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function destroy($id)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function gc($maxlifetime)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -41,10 +41,11 @@ class ProfilerListener implements EventSubscriberInterface
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param Profiler $profiler A Profiler instance
|
* @param Profiler $profiler A Profiler instance
|
||||||
* @param RequestMatcherInterface $matcher A RequestMatcher instance
|
* @param RequestMatcherInterface|null $matcher A RequestMatcher instance
|
||||||
* @param bool $onlyException true if the profiler only collects data when an exception occurs, false otherwise
|
* @param bool $onlyException true if the profiler only collects data when an exception occurs, false otherwise
|
||||||
* @param bool $onlyMasterRequests true if the profiler only collects data when the request is a master request, false otherwise
|
* @param bool $onlyMasterRequests true if the profiler only collects data when the request is a master request, false otherwise
|
||||||
|
* @param RequestStack|null $requestStack A RequestStack instance
|
||||||
*/
|
*/
|
||||||
public function __construct(Profiler $profiler, RequestMatcherInterface $matcher = null, $onlyException = false, $onlyMasterRequests = false, RequestStack $requestStack = null)
|
public function __construct(Profiler $profiler, RequestMatcherInterface $matcher = null, $onlyException = false, $onlyMasterRequests = false, RequestStack $requestStack = null)
|
||||||
{
|
{
|
||||||
|
@ -50,9 +50,10 @@ class RouterListener implements EventSubscriberInterface
|
|||||||
*
|
*
|
||||||
* RequestStack will become required in 3.0.
|
* RequestStack will become required in 3.0.
|
||||||
*
|
*
|
||||||
* @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
|
* @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
|
||||||
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
|
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
|
||||||
* @param LoggerInterface|null $logger The logger
|
* @param LoggerInterface|null $logger The logger
|
||||||
|
* @param RequestStack|null $requestStack A RequestStack instance
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
|
@ -34,7 +34,7 @@ class ExpressionVoter implements VoterInterface
|
|||||||
*
|
*
|
||||||
* @param ExpressionLanguage $expressionLanguage
|
* @param ExpressionLanguage $expressionLanguage
|
||||||
* @param AuthenticationTrustResolverInterface $trustResolver
|
* @param AuthenticationTrustResolverInterface $trustResolver
|
||||||
* @param RoleHierarchyInterface $roleHierarchy
|
* @param RoleHierarchyInterface|null $roleHierarchy
|
||||||
*/
|
*/
|
||||||
public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null)
|
public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null)
|
||||||
{
|
{
|
||||||
|
@ -50,8 +50,11 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
|
|||||||
* successful, or failed authentication attempt
|
* successful, or failed authentication attempt
|
||||||
* @param LoggerInterface $logger A LoggerInterface instance
|
* @param LoggerInterface $logger A LoggerInterface instance
|
||||||
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
|
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
|
||||||
* @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance
|
|
||||||
* @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance
|
* @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance
|
||||||
|
* @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException In case no simple authenticator is provided
|
||||||
|
* @throws InvalidArgumentException In case an invalid CSRF token manager is passed
|
||||||
*/
|
*/
|
||||||
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null)
|
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null)
|
||||||
{
|
{
|
||||||
|
@ -179,7 +179,7 @@ class PluralizationRules
|
|||||||
return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
|
return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2);
|
||||||
|
|
||||||
case 'ar':
|
case 'ar':
|
||||||
return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number >= 3) && ($number <= 10)) ? 3 : ((($number >= 11) && ($number <= 99)) ? 4 : 5))));
|
return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5))));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user