Ошибка при загрузке больших файлов превышающих upload_max_filesize в php.ini. Validate CSRF token
18.03.2014 yii, CSRFСтолкнулся с этой неизлечимой из корня бедой и я тоже. В сети много костылей по решению данной проблемы. Самый популярный костыль это
отключить проверку CSRF при определенном route
я не стал следовать этому совету и решил разобраться глубже. Первое что я сделал, это проверил что находится в момент ошибки в $_SERVER
и сделал выводы, используя которые было написано моё решение.
class HttpRequest extends CHttpRequest
{
/**
* @var array - Media types and the sub-types, which content the field for upload files
*/
public $contentType = array('multipart/form-data');
public function validateCsrfToken($event)
{
$currentType = explode(';', $_SERVER['CONTENT_TYPE']);
$contentLength = $_SERVER['CONTENT_LENGTH'];
if ($this->getIsPostRequest() && in_array($currentType[0], $this->contentType) && $contentLength)
{
if ($contentLength > $this->sizeToBytes(ini_get('upload_max_filesize')))
{
Yii::app()->user->setFlash('error', 'The file is too large.');
return true;
}
}
parent::validateCsrfToken($event);
}
/**
* Converts php.ini style size to bytes. Examples of size strings are: 150, 1g, 500k, 5M (size suffix
* is case insensitive). If you pass here the number with a fractional part, then everything after
* the decimal point will be ignored (php.ini values common behavior). For example 1.5G value would be
* treated as 1G and 1073741824 number will be returned as a result. This method is public
* (was private before) since 1.1.11.
*
* @param string $sizeStr the size string to convert.
* @return integer the byte count in the given size string.
* @since 1.1.11
*/
public function sizeToBytes($sizeStr)
{
// get the latest character
switch (strtolower(substr($sizeStr, -1)))
{
case 'm': return (int) $sizeStr * 1048576; // 1024 * 1024
case 'k': return (int) $sizeStr * 1024; // 1024
case 'g': return (int) $sizeStr * 1073741824; // 1024 * 1024 * 1024
default: return (int) $sizeStr; // do nothing
}
}
}
Данный код сравнивает $_SERVER['CONTENT_LENGTH']
с ini_get('upload_max_filesize')
. Если $_SERVER['CONTENT_LENGTH'] > ini_get('upload_max_filesize')
, то выводится соответствующее сообщение. Его можно поменять, убрать или ещё что-нибудь. В свойстве $contentType
класса HttpRequest
содержится массив с media-типами, к которым следует применять данное решение.
Возможно, это не самое лучшее решение, но меня оно устраивает полностью.
Внимание! У некоторых могут возникнуть проблемы с конфликтом имён класса, т.к. класс HttpRequest
есть в HTTP extension http://www.php.net/manual/en/class.httprequest.php . Чтобы решить данную проблему добавляем любой префикс в имя класса или используем namespace.