Ошибка при загрузке больших файлов превышающих 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.