code:
/**
 * NetteForms - simple form validation.
 *
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

(function(global, factory) {
	if (typeof define === 'function' && define.amd) {
		define(function() {
			return factory(global);
		});
	} else if (typeof module === 'object' && typeof module.exports === 'object') {
		module.exports = factory(global);
	} else {
		global.Nette = factory(global);
		global.Nette.initOnLoad();
	}

}(typeof window !== 'undefined' ? window : this, function(window) {

'use strict';

var Nette = {};

/**
 * Attaches a handler to an event for the element.
 */
Nette.addEvent = function(element, on, callback) {
	var original = element['on' + on];
	element['on' + on] = function() {
		if (typeof original === 'function' && original.apply(element, arguments) === false) {
			return false;
		}
		return callback.apply(element, arguments);
	};
};

/**
 * Returns the value of form element.
 */
Nette.getValue = function(elem) {
	var i;
	if (!elem) {
		return null;

	} else if (!elem.tagName) { // RadioNodeList, HTMLCollection, array
		return elem[0] ? Nette.getValue(elem[0]) : null;

	} else if (elem.type === 'radio') {
		var elements = elem.form.elements; // prevents problem with name 'item' or 'namedItem'
		for (i = 0; i < elements.length; i++) {
			if (elements[i].name === elem.name && elements[i].checked) {
				return elements[i].value;
			}
		}
		return null;

	} else if (elem.type === 'file') {
		return elem.files || elem.value;

	} else if (elem.tagName.toLowerCase() === 'select') {
		var index = elem.selectedIndex,
			options = elem.options,
			values = [];

		if (elem.type === 'select-one') {
			return index < 0 ? null : options[index].value;
		}

		for (i = 0; i < options.length; i++) {
			if (options[i].selected) {
				values.push(options[i].value);
			}
		}
		return values;

	} else if (elem.name && elem.name.match(/\[\]$/)) { // multiple elements []
		var elements = elem.form.elements[elem.name].tagName ? [elem] : elem.form.elements[elem.name],
			values = [];

		for (i = 0; i < elements.length; i++) {
			if (elements[i].type !== 'checkbox' || elements[i].checked) {
				values.push(elements[i].value);
			}
		}
		return values;

	} else if (elem.type === 'checkbox') {
		return elem.checked;

	} else if (elem.tagName.toLowerCase() === 'textarea') {
		return elem.value.replace("\r", '');

	} else {
		return elem.value.replace("\r", '').replace(/^\s+|\s+$/g, '');
	}
};

/**
 * Returns the effective value of form element.
 */
Nette.getEffectiveValue = function(elem) {
	var val = Nette.getValue(elem);
	if (elem.getAttribute) {
		if (val === elem.getAttribute('data-nette-empty-value')) {
			val = '';
		}
	}
	return val;
};

/**
 * Validates form element against given rules.
 */
Nette.validateControl = function(elem, rules, onlyCheck, value) {
	elem = elem.tagName ? elem : elem[0]; // RadioNodeList
	rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;

	for (var id = 0, len = rules.length; id < len; id++) {
		var rule = rules[id],
			op = rule.op.match(/(~)?([^?]+)/),
			curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;

		if (!curElem) {
			continue;
		}

		rule.neg = op[1];
		rule.op = op[2];
		rule.condition = !!rule.rules;
		curElem = curElem.tagName ? curElem : curElem[0]; // RadioNodeList

		var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)},
			success = Nette.validateRule(curElem, rule.op, rule.arg, curValue);

		if (success === null) {
			continue;
		} else if (rule.neg) {
			success = !success;
		}

		if (rule.condition && success) {
			if (!Nette.validateControl(elem, rule.rules, onlyCheck, value)) {
				return false;
			}
		} else if (!rule.condition && !success) {
			if (Nette.isDisabled(curElem)) {
				continue;
			}
			if (!onlyCheck) {
				var arr = Nette.isArray(rule.arg) ? rule.arg : [rule.arg],
					message = rule.msg.replace(/%(value|\d+)/g, function(foo, m) {
						return Nette.getValue(m === 'value' ? curElem : elem.form.elements.namedItem(arr[m].control));
					});
				Nette.addError(curElem, message);
			}
			return false;
		}
	}
	return true;
};

/**
 * Validates whole form.
 */
Nette.validateForm = function(sender) {
	var form = sender.form || sender,
		scope = false;

	if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) {
		var scopeArr = Nette.parseJSON(form['nette-submittedBy'].getAttribute('data-nette-validation-scope'));
		if (scopeArr.length) {
			scope = new RegExp('^(' + scopeArr.join('-|') + '-)');
		} else {
			return true;
		}
	}

	var radios = {}, i, elem;

	for (i = 0; i < form.elements.length; i++) {
		elem = form.elements[i];

		if (elem.tagName && !(elem.tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1})) {
			continue;

		} else if (elem.type === 'radio') {
			if (radios[elem.name]) {
				continue;
			}
			radios[elem.name] = true;
		}

		if ((scope && !elem.name.replace(/]\[|\[|]|$/g, '-').match(scope)) || Nette.isDisabled(elem)) {
			continue;
		}

		if (!Nette.validateControl(elem)) {
			return false;
		}
	}
	return true;
};

/**
 * Check if input is disabled.
 */
Nette.isDisabled = function(elem) {
	if (elem.type === 'radio') {
		for (var i = 0, elements = elem.form.elements; i < elements.length; i++) {
			if (elements[i].name === elem.name && !elements[i].disabled) {
				return false;
			}
		}
		return true;
	}
	return elem.disabled;
};

/**
 * Display error message.
 */
Nette.addError = function(elem, message) {
	if (message) {
		alert(message);
	}
	if (elem.focus) {
		elem.focus();
	}
};

/**
 * Expand rule argument.
 */
Nette.expandRuleArgument = function(form, arg) {
	if (arg && arg.control) {
		arg = Nette.getEffectiveValue(form.elements.namedItem(arg.control));
	}
	return arg;
};

/**
 * Validates single rule.
 */
Nette.validateRule = function(elem, op, arg, value) {
	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;

	if (op.charAt(0) === ':') {
		op = op.substr(1);
	}
	op = op.replace('::', '_');
	op = op.replace(/\\/g, '');

	var arr = Nette.isArray(arg) ? arg.slice(0) : [arg];
	for (var i = 0, len = arr.length; i < len; i++) {
		arr[i] = Nette.expandRuleArgument(elem.form, arr[i]);
	}
	return Nette.validators[op]
		? Nette.validators[op](elem, Nette.isArray(arg) ? arr : arr[0], value.value, value)
		: null;
};

Nette.validators = {
	filled: function(elem, arg, val) {
		return val !== '' && val !== false && val !== null
			&& (!Nette.isArray(val) || !!val.length)
			&& (!window.FileList || !(val instanceof window.FileList) || val.length);
	},

	blank: function(elem, arg, val) {
		return !Nette.validators.filled(elem, arg, val);
	},

	valid: function(elem, arg, val) {
		return Nette.validateControl(elem, null, true);
	},

	equal: function(elem, arg, val) {
		if (arg === undefined) {
			return null;
		}

		function toString(val) {
			if (typeof val === 'number' || typeof val === 'string') {
				return '' + val;
			} else {
				return val === true ? '1' : '';
			}
		}

		val = Nette.isArray(val) ? val : [val];
		arg = Nette.isArray(arg) ? arg : [arg];
		loop:
		for (var i1 = 0, len1 = val.length; i1 < len1; i1++) {
			for (var i2 = 0, len2 = arg.length; i2 < len2; i2++) {
				if (toString(val[i1]) === toString(arg[i2])) {
					continue loop;
				}
			}
			return false;
		}
		return true;
	},

	notEqual: function(elem, arg, val) {
		return arg === undefined ? null : !Nette.validators.equal(elem, arg, val);
	},

	minLength: function(elem, arg, val) {
		return val.length >= arg;
	},

	maxLength: function(elem, arg, val) {
		return val.length <= arg;
	},

	length: function(elem, arg, val) {
		arg = Nette.isArray(arg) ? arg : [arg, arg];
		return (arg[0] === null || val.length >= arg[0]) && (arg[1] === null || val.length <= arg[1]);
	},

	email: function(elem, arg, val) {
		return (/^("([ !#-[\]-~]|\\[ -~])+"|[-a-z0-9!#$%&'*+\/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+\/=?^_`{|}~]+)*)@([0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)+[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?$/i).test(val);
	},

	url: function(elem, arg, val, value) {
		if (!(/^[a-z\d+.-]+:/).test(val)) {
			val = 'http://' + val;
		}
		if ((/^https?:\/\/((([-_0-9a-z\u00C0-\u02FF\u0370-\u1EFF]+\.)*[0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)?[a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[0-9a-f:]{3,39}\])(:\d{1,5})?(\/\S*)?$/i).test(val)) {
			value.value = val;
			return true;
		}
		return false;
	},

	regexp: function(elem, arg, val) {
		var parts = typeof arg === 'string' ? arg.match(/^\/(.*)\/([imu]*)$/) : false;
		try {
			return parts && (new RegExp(parts[1], parts[2].replace('u', ''))).test(val);
		} catch (e) {}
	},

	pattern: function(elem, arg, val) {
		try {
			return typeof arg === 'string' ? (new RegExp('^(?:' + arg + ')$')).test(val) : null;
		} catch (e) {}
	},

	integer: function(elem, arg, val) {
		return (/^-?[0-9]+$/).test(val);
	},

	'float': function(elem, arg, val, value) {
		val = val.replace(' ', '').replace(',', '.');
		if ((/^-?[0-9]*[.,]?[0-9]+$/).test(val)) {
			value.value = val;
			return true;
		}
		return false;
	},

	min: function(elem, arg, val) {
		return Nette.validators.range(elem, [arg, null], val);
	},

	max: function(elem, arg, val) {
		return Nette.validators.range(elem, [null, arg], val);
	},

	range: function(elem, arg, val) {
		return Nette.isArray(arg) ?
			((arg[0] === null || parseFloat(val) >= arg[0]) && (arg[1] === null || parseFloat(val) <= arg[1])) : null;
	},

	submitted: function(elem, arg, val) {
		return elem.form['nette-submittedBy'] === elem;
	},

	fileSize: function(elem, arg, val) {
		if (window.FileList) {
			for (var i = 0; i < val.length; i++) {
				if (val[i].size > arg) {
					return false;
				}
			}
		}
		return true;
	},

	image: function (elem, arg, val) {
		if (window.FileList && val instanceof window.FileList) {
			for (var i = 0; i < val.length; i++) {
				var type = val[i].type;
				if (type && type !== 'image/gif' && type !== 'image/png' && type !== 'image/jpeg') {
					return false;
				}
			}
		}
		return true;
	}
};

/**
 * Process all toggles in form.
 */
Nette.toggleForm = function(form, elem) {
	var i;
	Nette.toggles = {};
	for (i = 0; i < form.elements.length; i++) {
		if (form.elements[i].tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
			Nette.toggleControl(form.elements[i], null, null, !elem);
		}
	}

	for (i in Nette.toggles) {
		Nette.toggle(i, Nette.toggles[i], elem);
	}
};

/**
 * Process toggles on form element.
 */
Nette.toggleControl = function(elem, rules, success, firsttime, value) {
	rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
	value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;

	var has = false,
		handled = [],
		handler = function () {
			Nette.toggleForm(elem.form, elem);
		},
		curSuccess;

	for (var id = 0, len = rules.length; id < len; id++) {
		var rule = rules[id],
			op = rule.op.match(/(~)?([^?]+)/),
			curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;

		if (!curElem) {
			continue;
		}

		curSuccess = success;
		if (success !== false) {
			rule.neg = op[1];
			rule.op = op[2];
			var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)};
			curSuccess = Nette.validateRule(curElem, rule.op, rule.arg, curValue);
			if (curSuccess === null) {
				continue;

			} else if (rule.neg) {
				curSuccess = !curSuccess;
			}
			if (!rule.rules) {
				success = curSuccess;
			}
		}

		if ((rule.rules && Nette.toggleControl(elem, rule.rules, curSuccess, firsttime, value)) || rule.toggle) {
			has = true;
			if (firsttime) {
				var oldIE = !document.addEventListener, // IE < 9
					name = curElem.tagName ? curElem.name : curElem[0].name,
					els = curElem.tagName ? curElem.form.elements : curElem;

				for (var i = 0; i < els.length; i++) {
					if (els[i].name === name && !Nette.inArray(handled, els[i])) {
						Nette.addEvent(els[i], oldIE && els[i].type in {checkbox: 1, radio: 1} ? 'click' : 'change', handler);
						handled.push(els[i]);
					}
				}
			}
			for (var id2 in rule.toggle || []) {
				if (Object.prototype.hasOwnProperty.call(rule.toggle, id2)) {
					Nette.toggles[id2] = Nette.toggles[id2] || (rule.toggle[id2] ? curSuccess : !curSuccess);
				}
			}
		}
	}
	return has;
};

Nette.parseJSON = function(s) {
	s = s || '[]';
	if (s.substr(0, 3) === '{op') {
		return eval('[' + s + ']'); // backward compatibility
	}
	return window.JSON && window.JSON.parse ? JSON.parse(s) : eval(s);
};

/**
 * Displays or hides HTML element.
 */
Nette.toggle = function(id, visible, srcElement) {
	var elem = document.getElementById(id);
	if (elem) {
		elem.style.display = visible ? '' : 'none';
	}
};

/**
 * Setup handlers.
 */
Nette.initForm = function(form) {
	form.noValidate = 'novalidate';

	Nette.addEvent(form, 'submit', function(e) {
		if (!Nette.validateForm(form)) {
			if (e && e.stopPropagation) {
				e.stopPropagation();
			} else if (window.event) {
				event.cancelBubble = true;
			}
			return false;
		}
	});

	Nette.addEvent(form, 'click', function(e) {
		e = e || event;
		var target = e.target || e.srcElement;
		form['nette-submittedBy'] = (target.type in {submit: 1, image: 1}) ? target : null;
	});

	Nette.toggleForm(form);
};

/**
 * @private
 */
Nette.initOnLoad = function() {
	Nette.addEvent(window, 'load', function() {
		for (var i = 0; i < document.forms.length; i++) {
			var form = document.forms[i];
			for (var j = 0; j < form.elements.length; j++) {
				if (form.elements[j].getAttribute('data-nette-rules')) {
					Nette.initForm(form);
					break;
				}
			}
		}
	});
};

/**
 * Determines whether the argument is an array.
 */
Nette.isArray = function(arg) {
	return Object.prototype.toString.call(arg) === '[object Array]';
};

/**
 * Search for a specified value within an array.
 */
Nette.inArray = function(arr, val) {
	if ([].indexOf) {
		return arr.indexOf(val) > -1;
	} else {
		for (var i = 0; i < arr.length; i++) {
			if (arr[i] === val) {
				return true;
			}
		}
		return false;
	}
};

/**
 * Converts string to web safe characters [a-z0-9-] text.
 */
Nette.webalize = function(s) {
	s = s.toLowerCase();
	var res = '', i, ch;
	for (i = 0; i < s.length; i++) {
		ch = Nette.webalizeTable[s.charAt(i)];
		res += ch ? ch : s.charAt(i);
	}
	return res.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
};

Nette.webalizeTable = {\u00e1: 'a', \u00e4: 'a', \u010d: 'c', \u010f: 'd', \u00e9: 'e', \u011b: 'e', \u00ed: 'i', \u013e: 'l', \u0148: 'n', \u00f3: 'o', \u00f4: 'o', \u0159: 'r', \u0161: 's', \u0165: 't', \u00fa: 'u', \u016f: 'u', \u00fd: 'y', \u017e: 'z'};

return Nette;
}));


nette/http

description: Nette HTTP Component

ext-fileinfo: to detect type of uploaded files

minimum-stability: dev

repo_name: Cerx/ToDo

license: mit


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Bridges\HttpDI;

use Nette;

/**
 * HTTP extension for Nette DI.
 */
class HttpExtension extends Nette\DI\CompilerExtension
{
	public $defaults = array(
		'proxy' => array(),
		'headers' => array(
			'X-Powered-By' => 'Nette Framework',
			'Content-Type' => 'text/html; charset=utf-8',
		),
		'frames' => 'SAMEORIGIN', // X-Frame-Options
	);

	public function loadConfiguration()
	{
		$container = $this->getContainerBuilder();
		$config = $this->validateConfig($this->defaults);

		$container->addDefinition($this->prefix('requestFactory'))
			->setClass('Nette\Http\RequestFactory')
			->addSetup('setProxy', array($config['proxy']));

		$container->addDefinition($this->prefix('request'))
			->setClass('Nette\Http\Request')
			->setFactory('@Nette\Http\RequestFactory::createHttpRequest');

		$container->addDefinition($this->prefix('response'))
			->setClass('Nette\Http\Response');

		$container->addDefinition($this->prefix('context'))
			->setClass('Nette\Http\Context');

		if ($this->name === 'http') {
			$container->addAlias('nette.httpRequestFactory', $this->prefix('requestFactory'));
			$container->addAlias('nette.httpContext', $this->prefix('context'));
			$container->addAlias('httpRequest', $this->prefix('request'));
			$container->addAlias('httpResponse', $this->prefix('response'));
		}
	}

	public function afterCompile(Nette\PhpGenerator\ClassType $class)
	{
		if (PHP_SAPI === 'cli') {
			return;
		}

		$initialize = $class->getMethod('initialize');
		$config = $this->getConfig();

		if (isset($config['frames']) && $config['frames'] !== TRUE) {
			$frames = $config['frames'];
			if ($frames === FALSE) {
				$frames = 'DENY';
			} elseif (preg_match('#^https?:#', $frames)) {
				$frames = "ALLOW-FROM $frames";
			}
			$initialize->addBody('header(?);', array("X-Frame-Options: $frames"));
		}

		foreach ($config['headers'] as $key => $value) {
			if ($value != NULL) { // intentionally ==
				$initialize->addBody('header(?);', array("$key: $value"));
			}
		}
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Bridges\HttpDI;

use Nette;

/**
 * Session extension for Nette DI.
 */
class SessionExtension extends Nette\DI\CompilerExtension
{
	public $defaults = array(
		'debugger' => FALSE,
		'autoStart' => 'smart', // true|false|smart
		'expiration' => NULL,
	);

	/** @var bool */
	private $debugMode;

	public function __construct($debugMode = FALSE)
	{
		$this->debugMode = $debugMode;
	}

	public function loadConfiguration()
	{
		$container = $this->getContainerBuilder();
		$config = $this->getConfig() + $this->defaults;
		$this->setConfig($config);

		$session = $container->addDefinition($this->prefix('session'))
			->setClass('Nette\Http\Session');

		if ($config['expiration']) {
			$session->addSetup('setExpiration', array($config['expiration']));
		}

		if ($this->debugMode && $config['debugger']) {
			$session->addSetup('@Tracy\Bar::addPanel', array(
				new Nette\DI\Statement('Nette\Bridges\HttpTracy\SessionPanel'),
			));
		}

		unset($config['expiration'], $config['autoStart'], $config['debugger']);
		if (!empty($config)) {
			$session->addSetup('setOptions', array($config));
		}

		if ($this->name === 'session') {
			$container->addAlias('session', $this->prefix('session'));
		}
	}

	public function afterCompile(Nette\PhpGenerator\ClassType $class)
	{
		if (PHP_SAPI === 'cli') {
			return;
		}

		$initialize = $class->getMethod('initialize');
		$config = $this->getConfig();
		$name = $this->prefix('session');

		if ($config['autoStart'] === 'smart') {
			$initialize->addBody('$this->getService(?)->exists() && $this->getService(?)->start();', array($name, $name));

		} elseif ($config['autoStart']) {
			$initialize->addBody('$this->getService(?)->start();', array($name));
		}
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Bridges\HttpTracy;

use Nette;
use Tracy;

/**
 * Session panel for Debugger Bar.
 */
class SessionPanel extends Nette\Object implements Tracy\IBarPanel
{

	/**
	 * Renders tab.
	 * @return string
	 */
	public function getTab()
	{
		ob_start(function () {});
		require __DIR__ . '/templates/SessionPanel.tab.phtml';
		return ob_get_clean();
	}

	/**
	 * Renders panel.
	 * @return string
	 */
	public function getPanel()
	{
		ob_start(function () {});
		require __DIR__ . '/templates/SessionPanel.panel.phtml';
		return ob_get_clean();
	}

}


code:
<?php

namespace Nette\Bridges\HttpTracy;

use Nette,
	Tracy\Dumper;

?>

Session #<?php echo htmlspecialchars(session_id(), ENT_IGNORE, 'UTF-8') ?> (Lifetime: <?php echo htmlspecialchars(ini_get('session.cookie_lifetime'), ENT_NOQUOTES, 'UTF-8'); ?>)

		<?php if (empty($_SESSION)):?>

empty

		<?php else: ?>

		<?php
		foreach ($_SESSION as $k => $v) {
			if ($k === '__NF') {
				$k = 'Nette Session'; $v = isset($v['DATA']) ? $v['DATA'] : NULL;
			}
			echo '
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	', Dumper::toHtml($v, array(Dumper::LIVE => TRUE)), "
\n";
		}?>

		<?php endif ?>


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;

/**
 * HTTP-specific tasks.
 */
class Context extends Nette\Object
{
	/** @var IRequest */
	private $request;

	/** @var IResponse */
	private $response;

	public function __construct(IRequest $request, IResponse $response)
	{
		$this->request = $request;
		$this->response = $response;
	}

	/**
	 * Attempts to cache the sent entity by its last modification date.
	 * @param  string|int|\DateTime  last modified time
	 * @param  string  strong entity tag validator
	 * @return bool
	 */
	public function isModified($lastModified = NULL, $etag = NULL)
	{
		if ($lastModified) {
			$this->response->setHeader('Last-Modified', Helpers::formatDate($lastModified));
		}
		if ($etag) {
			$this->response->setHeader('ETag', '"' . addslashes($etag) . '"');
		}

		$ifNoneMatch = $this->request->getHeader('If-None-Match');
		if ($ifNoneMatch === '*') {
			$match = TRUE; // match, check if-modified-since

		} elseif ($ifNoneMatch !== NULL) {
			$etag = $this->response->getHeader('ETag');

			if ($etag == NULL || strpos(' ' . strtr($ifNoneMatch, ",\t", '  '), ' ' . $etag) === FALSE) {
				return TRUE;

			} else {
				$match = TRUE; // match, check if-modified-since
			}
		}

		$ifModifiedSince = $this->request->getHeader('If-Modified-Since');
		if ($ifModifiedSince !== NULL) {
			$lastModified = $this->response->getHeader('Last-Modified');
			if ($lastModified != NULL && strtotime($lastModified) <= strtotime($ifModifiedSince)) {
				$match = TRUE;

			} else {
				return TRUE;
			}
		}

		if (empty($match)) {
			return TRUE;
		}

		$this->response->setCode(IResponse::S304_NOT_MODIFIED);
		return FALSE;
	}

	/**
	 * @return IRequest
	 */
	public function getRequest()
	{
		return $this->request;
	}

	/**
	 * @return IResponse
	 */
	public function getResponse()
	{
		return $this->response;
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;

/**
 * Provides access to individual files that have been uploaded by a client.
 *
 * @property-read string $name
 * @property-read string $sanitizedName
 * @property-read string|NULL $contentType
 * @property-read int $size
 * @property-read string $temporaryFile
 * @property-read int $error
 * @property-read bool $ok
 * @property-read string|NULL $contents
 */
class FileUpload extends Nette\Object
{
	/** @var string */
	private $name;

	/** @var string */
	private $type;

	/** @var string */
	private $size;

	/** @var string */
	private $tmpName;

	/** @var int */
	private $error;

	public function __construct($value)
	{
		foreach (array('name', 'type', 'size', 'tmp_name', 'error') as $key) {
			if (!isset($value[$key]) || !is_scalar($value[$key])) {
				$this->error = UPLOAD_ERR_NO_FILE;
				return; // or throw exception?
			}
		}
		$this->name = $value['name'];
		$this->size = $value['size'];
		$this->tmpName = $value['tmp_name'];
		$this->error = $value['error'];
	}

	/**
	 * Returns the file name.
	 * @return string
	 */
	public function getName()
	{
		return $this->name;
	}

	/**
	 * Returns the sanitized file name.
	 * @return string
	 */
	public function getSanitizedName()
	{
		return trim(Nette\Utils\Strings::webalize($this->name, '.', FALSE), '.-');
	}

	/**
	 * Returns the MIME content type of an uploaded file.
	 * @return string|NULL
	 */
	public function getContentType()
	{
		if ($this->isOk() && $this->type === NULL) {
			$this->type = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->tmpName);
		}
		return $this->type;
	}

	/**
	 * Returns the size of an uploaded file.
	 * @return int
	 */
	public function getSize()
	{
		return $this->size;
	}

	/**
	 * Returns the path to an uploaded file.
	 * @return string
	 */
	public function getTemporaryFile()
	{
		return $this->tmpName;
	}

	/**
	 * Returns the path to an uploaded file.
	 * @return string
	 */
	public function __toString()
	{
		return (string) $this->tmpName;
	}

	/**
	 * Returns the error code. {@link http://php.net/manual/en/features.file-upload.errors.php}
	 * @return int
	 */
	public function getError()
	{
		return $this->error;
	}

	/**
	 * Is there any error?
	 * @return bool
	 */
	public function isOk()
	{
		return $this->error === UPLOAD_ERR_OK;
	}

	/**
	 * Move uploaded file to new location.
	 * @param  string
	 * @return self
	 */
	public function move($dest)
	{
		@mkdir(dirname($dest), 0777, TRUE); // @ - dir may already exist
		@unlink($dest); // @ - file may not exists
		if (!call_user_func(is_uploaded_file($this->tmpName) ? 'move_uploaded_file' : 'rename', $this->tmpName, $dest)) {
			throw new Nette\InvalidStateException("Unable to move uploaded file '$this->tmpName' to '$dest'.");
		}
		@chmod($dest, 0666); // @ - possible low permission to chmod
		$this->tmpName = $dest;
		return $this;
	}

	/**
	 * Is uploaded file GIF, PNG or JPEG?
	 * @return bool
	 */
	public function isImage()
	{
		return in_array($this->getContentType(), array('image/gif', 'image/png', 'image/jpeg'), TRUE);
	}

	/**
	 * Returns the image.
	 * @return Nette\Utils\Image
	 * @throws Nette\Utils\ImageException
	 */
	public function toImage()
	{
		return Nette\Utils\Image::fromFile($this->tmpName);
	}

	/**
	 * Returns the dimensions of an uploaded image as array.
	 * @return array|NULL
	 */
	public function getImageSize()
	{
		return $this->isOk() ? @getimagesize($this->tmpName) : NULL; // @ - files smaller than 12 bytes causes read error
	}

	/**
	 * Get file contents.
	 * @return string|NULL
	 */
	public function getContents()
	{
		// future implementation can try to work around safe_mode and open_basedir limitations
		return $this->isOk() ? file_get_contents($this->tmpName) : NULL;
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;
use Nette\Utils\DateTime;

/**
 * Rendering helpers for HTTP.
 */
class Helpers
{

	/**
	 * Returns HTTP valid date format.
	 * @param  string|int|\DateTime
	 * @return string
	 */
	public static function formatDate($time)
	{
		$time = DateTime::from($time);
		$time->setTimezone(new \DateTimeZone('GMT'));
		return $time->format('D, d M Y H:i:s \G\M\T');
	}

	/**
	 * Is IP address in CIDR block?
	 * @return bool
	 */
	public static function ipMatch($ip, $mask)
	{
		list($mask, $size) = explode('/', $mask . '/');
		$tmp = function ($n) { return sprintf('%032b', $n); };
		$ip = implode('', array_map($tmp, unpack('N*', inet_pton($ip))));
		$mask = implode('', array_map($tmp, unpack('N*', inet_pton($mask))));
		$max = strlen($ip);
		if (!$max || $max !== strlen($mask) || $size < 0 || $size > $max) {
			return FALSE;
		}
		return strncmp($ip, $mask, $size === '' ? $max : $size) === 0;
	}

	/**
	 * Removes duplicate cookies from response.
	 * @return void
	 * @internal
	 */
	public static function removeDuplicateCookies()
	{
		if (headers_sent($file, $line) || ini_get('suhosin.cookie.encrypt')) {
			return;
		}

		$flatten = array();
		foreach (headers_list() as $header) {
			if (preg_match('#^Set-Cookie: .+?=#', $header, $m)) {
				$flatten[$m[0]] = $header;
				header_remove('Set-Cookie');
			}
		}
		foreach (array_values($flatten) as $key => $header) {
			header($header, $key === 0);
		}
	}

	/**
	 * @internal
	 */
	public static function stripSlashes($arr, $onlyKeys = FALSE)
	{
		$res = array();
		foreach ($arr as $k => $v) {
			$res[stripslashes($k)] = is_array($v)
				? self::stripSlashes($v, $onlyKeys)
				: ($onlyKeys ? $v : stripslashes($v));
		}
		return $res;
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

/**
 * IHttpRequest provides access scheme for request sent via HTTP.
 */
interface IRequest
{
	/** HTTP request method */
	const
		GET = 'GET',
		POST = 'POST',
		HEAD = 'HEAD',
		PUT = 'PUT',
		DELETE = 'DELETE',
		PATCH = 'PATCH';

	/**
	 * Returns URL object.
	 * @return UrlScript
	 */
	function getUrl();

	/********************* query, post, files & cookies ****************d*g**/

	/**
	 * Returns variable provided to the script via URL query ($_GET).
	 * If no key is passed, returns the entire array.
	 * @param  string key
	 * @param  mixed  default value
	 * @return mixed
	 */
	function getQuery($key = NULL, $default = NULL);

	/**
	 * Returns variable provided to the script via POST method ($_POST).
	 * If no key is passed, returns the entire array.
	 * @param  string key
	 * @param  mixed  default value
	 * @return mixed
	 */
	function getPost($key = NULL, $default = NULL);

	/**
	 * Returns uploaded file.
	 * @param  string key
	 * @return FileUpload|NULL
	 */
	function getFile($key);

	/**
	 * Returns uploaded files.
	 * @return array
	 */
	function getFiles();

	/**
	 * Returns variable provided to the script via HTTP cookies.
	 * @param  string key
	 * @param  mixed  default value
	 * @return mixed
	 */
	function getCookie($key, $default = NULL);

	/**
	 * Returns variables provided to the script via HTTP cookies.
	 * @return array
	 */
	function getCookies();

	/********************* method & headers ****************d*g**/

	/**
	 * Returns HTTP request method (GET, POST, HEAD, PUT, ...). The method is case-sensitive.
	 * @return string
	 */
	function getMethod();

	/**
	 * Checks HTTP request method.
	 * @param  string
	 * @return bool
	 */
	function isMethod($method);

	/**
	 * Return the value of the HTTP header. Pass the header name as the
	 * plain, HTTP-specified header name (e.g. 'Accept-Encoding').
	 * @param  string
	 * @param  mixed
	 * @return mixed
	 */
	function getHeader($header, $default = NULL);

	/**
	 * Returns all HTTP headers.
	 * @return array
	 */
	function getHeaders();

	/**
	 * Is the request is sent via secure channel (https).
	 * @return bool
	 */
	function isSecured();

	/**
	 * Is AJAX request?
	 * @return bool
	 */
	function isAjax();

	/**
	 * Returns the IP address of the remote client.
	 * @return string|NULL
	 */
	function getRemoteAddress();

	/**
	 * Returns the host of the remote client.
	 * @return string|NULL
	 */
	function getRemoteHost();

	/**
	 * Returns raw content of HTTP request body.
	 * @return string|NULL
	 */
	function getRawBody();

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

/**
 * IHttpResponse interface.
 */
interface IResponse
{
	/** @var int cookie expiration: forever (23.1.2037) */
	const PERMANENT = 2116333333;

	/** @var int cookie expiration: until the browser is closed */
	const BROWSER = 0;

	/** HTTP 1.1 response code */
	const
		S100_CONTINUE = 100,
		S101_SWITCHING_PROTOCOLS = 101,
		S200_OK = 200,
		S201_CREATED = 201,
		S202_ACCEPTED = 202,
		S203_NON_AUTHORITATIVE_INFORMATION = 203,
		S204_NO_CONTENT = 204,
		S205_RESET_CONTENT = 205,
		S206_PARTIAL_CONTENT = 206,
		S300_MULTIPLE_CHOICES = 300,
		S301_MOVED_PERMANENTLY = 301,
		S302_FOUND = 302,
		S303_SEE_OTHER = 303,
		S303_POST_GET = 303,
		S304_NOT_MODIFIED = 304,
		S305_USE_PROXY = 305,
		S307_TEMPORARY_REDIRECT = 307,
		S400_BAD_REQUEST = 400,
		S401_UNAUTHORIZED = 401,
		S402_PAYMENT_REQUIRED = 402,
		S403_FORBIDDEN = 403,
		S404_NOT_FOUND = 404,
		S405_METHOD_NOT_ALLOWED = 405,
		S406_NOT_ACCEPTABLE = 406,
		S407_PROXY_AUTHENTICATION_REQUIRED = 407,
		S408_REQUEST_TIMEOUT = 408,
		S409_CONFLICT = 409,
		S410_GONE = 410,
		S411_LENGTH_REQUIRED = 411,
		S412_PRECONDITION_FAILED = 412,
		S413_REQUEST_ENTITY_TOO_LARGE = 413,
		S414_REQUEST_URI_TOO_LONG = 414,
		S415_UNSUPPORTED_MEDIA_TYPE = 415,
		S416_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
		S417_EXPECTATION_FAILED = 417,
		S426_UPGRADE_REQUIRED = 426,
		S500_INTERNAL_SERVER_ERROR = 500,
		S501_NOT_IMPLEMENTED = 501,
		S502_BAD_GATEWAY = 502,
		S503_SERVICE_UNAVAILABLE = 503,
		S504_GATEWAY_TIMEOUT = 504,
		S505_HTTP_VERSION_NOT_SUPPORTED = 505;

	/**
	 * Sets HTTP response code.
	 * @param  int
	 * @return void
	 */
	function setCode($code);

	/**
	 * Returns HTTP response code.
	 * @return int
	 */
	function getCode();

	/**
	 * Sends a HTTP header and replaces a previous one.
	 * @param  string  header name
	 * @param  string  header value
	 * @return void
	 */
	function setHeader($name, $value);

	/**
	 * Adds HTTP header.
	 * @param  string  header name
	 * @param  string  header value
	 * @return void
	 */
	function addHeader($name, $value);

	/**
	 * Sends a Content-type HTTP header.
	 * @param  string  mime-type
	 * @param  string  charset
	 * @return void
	 */
	function setContentType($type, $charset = NULL);

	/**
	 * Redirects to a new URL.
	 * @param  string  URL
	 * @param  int     HTTP code
	 * @return void
	 */
	function redirect($url, $code = self::S302_FOUND);

	/**
	 * Sets the number of seconds before a page cached on a browser expires.
	 * @param  string|int|\DateTime  time, value 0 means "until the browser is closed"
	 * @return void
	 */
	function setExpiration($seconds);

	/**
	 * Checks if headers have been sent.
	 * @return bool
	 */
	function isSent();

	/**
	 * Returns value of an HTTP header.
	 * @param  string
	 * @param  mixed
	 * @return mixed
	 */
	function getHeader($header, $default = NULL);

	/**
	 * Returns a list of headers to sent.
	 * @return array (name => value)
	 */
	function getHeaders();

	/**
	 * Sends a cookie.
	 * @param  string name of the cookie
	 * @param  string value
	 * @param  mixed expiration as unix timestamp or number of seconds; Value 0 means "until the browser is closed"
	 * @param  string
	 * @param  string
	 * @param  bool
	 * @param  bool
	 * @return void
	 */
	function setCookie($name, $value, $expire, $path = NULL, $domain = NULL, $secure = NULL, $httpOnly = NULL);

	/**
	 * Deletes a cookie.
	 * @param  string name of the cookie.
	 * @param  string
	 * @param  string
	 * @param  bool
	 * @return void
	 */
	function deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL);

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

/**
 * User session storage for PHP < 5.4. @see http://php.net/session_set_save_handler
 *
 * @deprecated since PHP 5.4, use \SessionHandlerInterface
 */
interface ISessionStorage
{

	function open($savePath, $sessionName);

	function close();

	function read($id);

	function write($id, $data);

	function remove($id);

	function clean($maxlifetime);

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;

/**
 * HttpRequest provides access scheme for request sent via HTTP.
 *
 * @property-read UrlScript $url
 * @property-read array $query
 * @property-read array $post
 * @property-read array $files
 * @property-read array $cookies
 * @property-read string $method
 * @property-read array $headers
 * @property-read Url|NULL $referer
 * @property-read bool $secured
 * @property-read bool $ajax
 * @property-read string|NULL $remoteAddress
 * @property-read string|NULL $remoteHost
 * @property-read string|NULL $rawBody
 */
class Request extends Nette\Object implements IRequest
{
	/** @var string */
	private $method;

	/** @var UrlScript */
	private $url;

	/** @var array */
	private $post;

	/** @var array */
	private $files;

	/** @var array */
	private $cookies;

	/** @var array */
	private $headers;

	/** @var string|NULL */
	private $remoteAddress;

	/** @var string|NULL */
	private $remoteHost;

	/** @var callable|NULL */
	private $rawBodyCallback;

	public function __construct(UrlScript $url, $query = NULL, $post = NULL, $files = NULL, $cookies = NULL,
		$headers = NULL, $method = NULL, $remoteAddress = NULL, $remoteHost = NULL, $rawBodyCallback = NULL)
	{
		$this->url = $url;
		if ($query !== NULL) {
			trigger_error('Nette\Http\Request::__construct(): parameter $query is deprecated.', E_USER_DEPRECATED);
			$url->setQuery($query);
		}
		$this->post = (array) $post;
		$this->files = (array) $files;
		$this->cookies = (array) $cookies;
		$this->headers = array_change_key_case((array) $headers, CASE_LOWER);
		$this->method = $method ?: 'GET';
		$this->remoteAddress = $remoteAddress;
		$this->remoteHost = $remoteHost;
		$this->rawBodyCallback = $rawBodyCallback;
	}

	/**
	 * Returns URL object.
	 * @return UrlScript
	 */
	public function getUrl()
	{
		return clone $this->url;
	}

	/********************* query, post, files & cookies ****************d*g**/

	/**
	 * Returns variable provided to the script via URL query ($_GET).
	 * If no key is passed, returns the entire array.
	 * @param  string key
	 * @param  mixed  default value
	 * @return mixed
	 */
	public function getQuery($key = NULL, $default = NULL)
	{
		if (func_num_args() === 0) {
			return $this->url->getQueryParameters();
		} else {
			return $this->url->getQueryParameter($key, $default);
		}
	}

	/**
	 * Returns variable provided to the script via POST method ($_POST).
	 * If no key is passed, returns the entire array.
	 * @param  string key
	 * @param  mixed  default value
	 * @return mixed
	 */
	public function getPost($key = NULL, $default = NULL)
	{
		if (func_num_args() === 0) {
			return $this->post;

		} elseif (isset($this->post[$key])) {
			return $this->post[$key];

		} else {
			return $default;
		}
	}

	/**
	 * Returns uploaded file.
	 * @param  string key
	 * @return FileUpload|NULL
	 */
	public function getFile($key)
	{
		if (func_num_args() > 1) {
			trigger_error('Calling getFile() with multiple keys is deprecated.', E_USER_DEPRECATED);
			return Nette\Utils\Arrays::get($this->files, func_get_args(), NULL);
		}

		return isset($this->files[$key]) ? $this->files[$key] : NULL;
	}

	/**
	 * Returns uploaded files.
	 * @return array
	 */
	public function getFiles()
	{
		return $this->files;
	}

	/**
	 * Returns variable provided to the script via HTTP cookies.
	 * @param  string key
	 * @param  mixed  default value
	 * @return mixed
	 */
	public function getCookie($key, $default = NULL)
	{
		return isset($this->cookies[$key]) ? $this->cookies[$key] : $default;
	}

	/**
	 * Returns variables provided to the script via HTTP cookies.
	 * @return array
	 */
	public function getCookies()
	{
		return $this->cookies;
	}

	/********************* method & headers ****************d*g**/

	/**
	 * Returns HTTP request method (GET, POST, HEAD, PUT, ...). The method is case-sensitive.
	 * @return string
	 */
	public function getMethod()
	{
		return $this->method;
	}

	/**
	 * Checks if the request method is the given one.
	 * @param  string
	 * @return bool
	 */
	public function isMethod($method)
	{
		return strcasecmp($this->method, $method) === 0;
	}

	/**
	 * @deprecated
	 */
	public function isPost()
	{
		return $this->isMethod('POST');
	}

	/**
	 * Return the value of the HTTP header. Pass the header name as the
	 * plain, HTTP-specified header name (e.g. 'Accept-Encoding').
	 * @param  string
	 * @param  mixed
	 * @return mixed
	 */
	public function getHeader($header, $default = NULL)
	{
		$header = strtolower($header);
		return isset($this->headers[$header]) ? $this->headers[$header] : $default;
	}

	/**
	 * Returns all HTTP headers.
	 * @return array
	 */
	public function getHeaders()
	{
		return $this->headers;
	}

	/**
	 * Returns referrer.
	 * @return Url|NULL
	 */
	public function getReferer()
	{
		return isset($this->headers['referer']) ? new Url($this->headers['referer']) : NULL;
	}

	/**
	 * Is the request is sent via secure channel (https).
	 * @return bool
	 */
	public function isSecured()
	{
		return $this->url->getScheme() === 'https';
	}

	/**
	 * Is AJAX request?
	 * @return bool
	 */
	public function isAjax()
	{
		return $this->getHeader('X-Requested-With') === 'XMLHttpRequest';
	}

	/**
	 * Returns the IP address of the remote client.
	 * @return string|NULL
	 */
	public function getRemoteAddress()
	{
		return $this->remoteAddress;
	}

	/**
	 * Returns the host of the remote client.
	 * @return string|NULL
	 */
	public function getRemoteHost()
	{
		if ($this->remoteHost === NULL && $this->remoteAddress !== NULL) {
			$this->remoteHost = getHostByAddr($this->remoteAddress);
		}
		return $this->remoteHost;
	}

	/**
	 * Returns raw content of HTTP request body.
	 * @return string|NULL
	 */
	public function getRawBody()
	{
		return $this->rawBodyCallback ? call_user_func($this->rawBodyCallback) : NULL;
	}

	/**
	 * Parse Accept-Language header and returns preferred language.
	 * @param  string[] supported languages
	 * @return string|NULL
	 */
	public function detectLanguage(array $langs)
	{
		$header = $this->getHeader('Accept-Language');
		if (!$header) {
			return NULL;
		}

		$s = strtolower($header);  // case insensitive
		$s = strtr($s, '_', '-');  // cs_CZ means cs-CZ
		rsort($langs);             // first more specific
		preg_match_all('#(' . implode('|', $langs) . ')(?:-[^\s,;=]+)?\s*(?:;\s*q=([0-9.]+))?#', $s, $matches);

		if (!$matches[0]) {
			return NULL;
		}

		$max = 0;
		$lang = NULL;
		foreach ($matches[1] as $key => $value) {
			$q = $matches[2][$key] === '' ? 1.0 : (float) $matches[2][$key];
			if ($q > $max) {
				$max = $q;
				$lang = $value;
			}
		}

		return $lang;
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;
use Nette\Utils\Strings;

/**
 * Current HTTP request factory.
 */
class RequestFactory extends Nette\Object
{
	/** @internal */
	const CHARS = '\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}';

	/** @var array */
	public $urlFilters = array(
		'path' => array('#/{2,}#' => '/'), // '%20' => ''
		'url' => array(), // '#[.,)]\z#' => ''
	);

	/** @var bool */
	private $binary = FALSE;

	/** @var array */
	private $proxies = array();

	/**
	 * @param  bool
	 * @return self
	 */
	public function setBinary($binary = TRUE)
	{
		$this->binary = (bool) $binary;
		return $this;
	}

	/**
	 * @param  array|string
	 * @return self
	 */
	public function setProxy($proxy)
	{
		$this->proxies = (array) $proxy;
		return $this;
	}

	/**
	 * Creates current HttpRequest object.
	 * @return Request
	 */
	public function createHttpRequest()
	{
		// DETECTS URI, base path and script path of the request.
		$url = new UrlScript;
		$url->setScheme(!empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https' : 'http');
		$url->setUser(isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '');
		$url->setPassword(isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '');

		// host & port
		if ((isset($_SERVER[$tmp = 'HTTP_HOST']) || isset($_SERVER[$tmp = 'SERVER_NAME']))
			&& preg_match('#^([a-z0-9_.-]+|\[[a-f0-9:]+\])(:\d+)?\z#i', $_SERVER[$tmp], $pair)
		) {
			$url->setHost(strtolower($pair[1]));
			if (isset($pair[2])) {
				$url->setPort(substr($pair[2], 1));
			} elseif (isset($_SERVER['SERVER_PORT'])) {
				$url->setPort($_SERVER['SERVER_PORT']);
			}
		}

		// path & query
		$requestUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
		$requestUrl = Strings::replace($requestUrl, $this->urlFilters['url']);
		$tmp = explode('?', $requestUrl, 2);
		$path = Url::unescape($tmp[0], '%/?#');
		$path = Strings::fixEncoding(Strings::replace($path, $this->urlFilters['path']));
		$url->setPath($path);
		$url->setQuery(isset($tmp[1]) ? $tmp[1] : '');

		// detect script path
		$lpath = strtolower($path);
		$script = isset($_SERVER['SCRIPT_NAME']) ? strtolower($_SERVER['SCRIPT_NAME']) : '';
		if ($lpath !== $script) {
			$max = min(strlen($lpath), strlen($script));
			for ($i = 0; $i < $max && $lpath[$i] === $script[$i]; $i++);
			$path = $i ? substr($path, 0, strrpos($path, '/', $i - strlen($path) - 1) + 1) : '/';
		}
		$url->setScriptPath($path);

		// GET, POST, COOKIE
		$useFilter = (!in_array(ini_get('filter.default'), array('', 'unsafe_raw')) || ini_get('filter.default_flags'));

		$query = $url->getQueryParameters();
		$post = $useFilter ? filter_input_array(INPUT_POST, FILTER_UNSAFE_RAW) : (empty($_POST) ? array() : $_POST);
		$cookies = $useFilter ? filter_input_array(INPUT_COOKIE, FILTER_UNSAFE_RAW) : (empty($_COOKIE) ? array() : $_COOKIE);

		if (get_magic_quotes_gpc()) {
			$post = Helpers::stripslashes($post, $useFilter);
			$cookies = Helpers::stripslashes($cookies, $useFilter);
		}

		// remove invalid characters
		$reChars = '#^[' . self::CHARS . ']*+\z#u';
		if (!$this->binary) {
			$list = array(& $query, & $post, & $cookies);
			while (list($key, $val) = each($list)) {
				foreach ($val as $k => $v) {
					if (is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
						unset($list[$key][$k]);

					} elseif (is_array($v)) {
						$list[$key][$k] = $v;
						$list[] = & $list[$key][$k];

					} else {
						$list[$key][$k] = (string) preg_replace('#[^' . self::CHARS . ']+#u', '', $v);
					}
				}
			}
			unset($list, $key, $val, $k, $v);
		}
		$url->setQuery($query);

		// FILES and create FileUpload objects
		$files = array();
		$list = array();
		if (!empty($_FILES)) {
			foreach ($_FILES as $k => $v) {
				if (!$this->binary && is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
					continue;
				}
				$v['@'] = & $files[$k];
				$list[] = $v;
			}
		}

		while (list(, $v) = each($list)) {
			if (!isset($v['name'])) {
				continue;

			} elseif (!is_array($v['name'])) {
				if (get_magic_quotes_gpc()) {
					$v['name'] = stripSlashes($v['name']);
				}
				if (!$this->binary && (!preg_match($reChars, $v['name']) || preg_last_error())) {
					$v['name'] = '';
				}
				if ($v['error'] !== UPLOAD_ERR_NO_FILE) {
					$v['@'] = new FileUpload($v);
				}
				continue;
			}

			foreach ($v['name'] as $k => $foo) {
				if (!$this->binary && is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
					continue;
				}
				$list[] = array(
					'name' => $v['name'][$k],
					'type' => $v['type'][$k],
					'size' => $v['size'][$k],
					'tmp_name' => $v['tmp_name'][$k],
					'error' => $v['error'][$k],
					'@' => & $v['@'][$k],
				);
			}
		}

		// HEADERS
		if (function_exists('apache_request_headers')) {
			$headers = apache_request_headers();
		} else {
			$headers = array();
			foreach ($_SERVER as $k => $v) {
				if (strncmp($k, 'HTTP_', 5) == 0) {
					$k = substr($k, 5);
				} elseif (strncmp($k, 'CONTENT_', 8)) {
					continue;
				}
				$headers[ strtr($k, '_', '-') ] = $v;
			}
		}

		$remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
		$remoteHost = isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : NULL;

		// proxy
		foreach ($this->proxies as $proxy) {
			if (Helpers::ipMatch($remoteAddr, $proxy) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
				$proxies = $this->proxies;
				$xForwardedForWithoutProxies = array_filter(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']), function ($ip) use ($proxies) {
					return !array_filter($proxies, function ($proxy) use ($ip) {
						return Helpers::ipMatch(trim($ip), $proxy);
					});
				});
				$remoteAddr = trim(end($xForwardedForWithoutProxies));

				if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
					$xForwardedForRealIpKey = key($xForwardedForWithoutProxies);
					$xForwardedHost = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
					if (isset($xForwardedHost[$xForwardedForRealIpKey])) {
						$remoteHost = trim($xForwardedHost[$xForwardedForRealIpKey]);
					}
				}
				break;
			}
		}

		$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : NULL;
		if ($method === 'POST' && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])
			&& preg_match('#^[A-Z]+\z#', $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])
		) {
			$method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
		}

		// raw body
		$rawBodyCallback = function () {
			static $rawBody;

			if (PHP_VERSION_ID >= 50600) {
				return file_get_contents('php://input');

			} elseif ($rawBody === NULL) { // can be read only once in PHP < 5.6
				$rawBody = (string) file_get_contents('php://input');
			}

			return $rawBody;
		};

		return new Request($url, NULL, $post, $files, $cookies, $headers, $method, $remoteAddr, $remoteHost, $rawBodyCallback);
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;
use Nette\Utils\DateTime;

/**
 * HttpResponse class.
 */
class Response extends Nette\Object implements IResponse
{
	/** @var bool  Send invisible garbage for IE 6? */
	private static $fixIE = TRUE;

	/** @var string The domain in which the cookie will be available */
	public $cookieDomain = '';

	/** @var string The path in which the cookie will be available */
	public $cookiePath = '/';

	/** @var string Whether the cookie is available only through HTTPS */
	public $cookieSecure = FALSE;

	/** @var string Whether the cookie is hidden from client-side */
	public $cookieHttpOnly = TRUE;

	/** @var bool Whether warn on possible problem with data in output buffer */
	public $warnOnBuffer = TRUE;

	/** @var int HTTP response code */
	private $code = self::S200_OK;

	public function __construct()
	{
		if (PHP_VERSION_ID >= 50400) {
			if (is_int($code = http_response_code())) {
				$this->code = $code;
			}
		}

		if (PHP_VERSION_ID >= 50401) { // PHP bug #61106
			$rm = new \ReflectionMethod('Nette\Http\Helpers::removeDuplicateCookies');
			header_register_callback($rm->getClosure()); // requires closure due PHP bug #66375
		}
	}

	/**
	 * Sets HTTP response code.
	 * @param  int
	 * @return self
	 * @throws Nette\InvalidArgumentException  if code is invalid
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function setCode($code)
	{
		$code = (int) $code;
		if ($code < 100 || $code > 599) {
			throw new Nette\InvalidArgumentException("Bad HTTP response '$code'.");
		}
		self::checkHeaders();
		$this->code = $code;
		$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
		header($protocol . ' ' . $code, TRUE, $code);
		return $this;
	}

	/**
	 * Returns HTTP response code.
	 * @return int
	 */
	public function getCode()
	{
		return $this->code;
	}

	/**
	 * Sends a HTTP header and replaces a previous one.
	 * @param  string  header name
	 * @param  string  header value
	 * @return self
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function setHeader($name, $value)
	{
		self::checkHeaders();
		if ($value === NULL) {
			header_remove($name);
		} elseif (strcasecmp($name, 'Content-Length') === 0 && ini_get('zlib.output_compression')) {
			// ignore, PHP bug #44164
		} else {
			header($name . ': ' . $value, TRUE, $this->code);
		}
		return $this;
	}

	/**
	 * Adds HTTP header.
	 * @param  string  header name
	 * @param  string  header value
	 * @return self
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function addHeader($name, $value)
	{
		self::checkHeaders();
		header($name . ': ' . $value, FALSE, $this->code);
		return $this;
	}

	/**
	 * Sends a Content-type HTTP header.
	 * @param  string  mime-type
	 * @param  string  charset
	 * @return self
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function setContentType($type, $charset = NULL)
	{
		$this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
		return $this;
	}

	/**
	 * Redirects to a new URL. Note: call exit() after it.
	 * @param  string  URL
	 * @param  int     HTTP code
	 * @return void
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function redirect($url, $code = self::S302_FOUND)
	{
		$this->setCode($code);
		$this->setHeader('Location', $url);
		if (preg_match('#^https?:|^\s*+[a-z0-9+.-]*+[^:]#i', $url)) {
			$escapedUrl = htmlSpecialChars($url, ENT_IGNORE | ENT_QUOTES, 'UTF-8');
			echo "
Redirect
\n\n
Please click here to continue.
";
		}
	}

	/**
	 * Sets the number of seconds before a page cached on a browser expires.
	 * @param  string|int|\DateTime  time, value 0 means "until the browser is closed"
	 * @return self
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function setExpiration($time)
	{
		if (!$time) { // no cache
			$this->setHeader('Cache-Control', 's-maxage=0, max-age=0, must-revalidate');
			$this->setHeader('Expires', 'Mon, 23 Jan 1978 10:00:00 GMT');
			return $this;
		}

		$time = DateTime::from($time);
		$this->setHeader('Cache-Control', 'max-age=' . ($time->format('U') - time()));
		$this->setHeader('Expires', Helpers::formatDate($time));
		return $this;
	}

	/**
	 * Checks if headers have been sent.
	 * @return bool
	 */
	public function isSent()
	{
		return headers_sent();
	}

	/**
	 * Returns value of an HTTP header.
	 * @param  string
	 * @param  mixed
	 * @return mixed
	 */
	public function getHeader($header, $default = NULL)
	{
		$header .= ':';
		$len = strlen($header);
		foreach (headers_list() as $item) {
			if (strncasecmp($item, $header, $len) === 0) {
				return ltrim(substr($item, $len));
			}
		}
		return $default;
	}

	/**
	 * Returns a list of headers to sent.
	 * @return array (name => value)
	 */
	public function getHeaders()
	{
		$headers = array();
		foreach (headers_list() as $header) {
			$a = strpos($header, ':');
			$headers[substr($header, 0, $a)] = (string) substr($header, $a + 2);
		}
		return $headers;
	}

	/**
	 * @deprecated
	 */
	public static function date($time = NULL)
	{
		return Helpers::formatDate($time);
	}

	/**
	 * @return void
	 */
	public function __destruct()
	{
		if (self::$fixIE && isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE ') !== FALSE
			&& in_array($this->code, array(400, 403, 404, 405, 406, 408, 409, 410, 500, 501, 505), TRUE)
			&& preg_match('#^text/html(?:;|$)#', $this->getHeader('Content-Type', 'text/html'))
		) {
			echo Nette\Utils\Random::generate(2e3, " \t\r\n"); // sends invisible garbage for IE
			self::$fixIE = FALSE;
		}
	}

	/**
	 * Sends a cookie.
	 * @param  string name of the cookie
	 * @param  string value
	 * @param  string|int|\DateTime  expiration time, value 0 means "until the browser is closed"
	 * @param  string
	 * @param  string
	 * @param  bool
	 * @param  bool
	 * @return self
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function setCookie($name, $value, $time, $path = NULL, $domain = NULL, $secure = NULL, $httpOnly = NULL)
	{
		self::checkHeaders();
		setcookie(
			$name,
			$value,
			$time ? DateTime::from($time)->format('U') : 0,
			$path === NULL ? $this->cookiePath : (string) $path,
			$domain === NULL ? $this->cookieDomain : (string) $domain,
			$secure === NULL ? $this->cookieSecure : (bool) $secure,
			$httpOnly === NULL ? $this->cookieHttpOnly : (bool) $httpOnly
		);
		Helpers::removeDuplicateCookies();
		return $this;
	}

	/**
	 * Deletes a cookie.
	 * @param  string name of the cookie.
	 * @param  string
	 * @param  string
	 * @param  bool
	 * @return void
	 * @throws Nette\InvalidStateException  if HTTP headers have been sent
	 */
	public function deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL)
	{
		$this->setCookie($name, FALSE, 0, $path, $domain, $secure);
	}

	/** @internal @deprecated */
	public function removeDuplicateCookies()
	{
		trigger_error('Use Nette\Http\Helpers::removeDuplicateCookies()', E_USER_WARNING);
	}

	private function checkHeaders()
	{
		if (headers_sent($file, $line)) {
			throw new Nette\InvalidStateException('Cannot send header after HTTP headers have been sent' . ($file ? " (output started at $file:$line)." : '.'));

		} elseif ($this->warnOnBuffer && ob_get_length() && !array_filter(ob_get_status(TRUE), function ($i) { return !$i['chunk_size']; })) {
			trigger_error('Possible problem: you are sending a HTTP header while already having some data in output buffer. Try Tracy\OutputDebugger or start session earlier.', E_USER_NOTICE);
		}
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;

/**
 * Provides access to session sections as well as session settings and management methods.
 */
class Session extends Nette\Object
{
	/** Default file lifetime is 3 hours */
	const DEFAULT_FILE_LIFETIME = 10800;

	/** @var bool  has been session ID regenerated? */
	private $regenerated;

	/** @var bool  has been session started? */
	private static $started;

	/** @var array default configuration */
	private $options = array(
		// security
		'referer_check' => '',    // must be disabled because PHP implementation is invalid
		'use_cookies' => 1,       // must be enabled to prevent Session Hijacking and Fixation
		'use_only_cookies' => 1,  // must be enabled to prevent Session Fixation
		'use_trans_sid' => 0,     // must be disabled to prevent Session Hijacking and Fixation

		// cookies
		'cookie_lifetime' => 0,   // until the browser is closed
		'cookie_path' => '/',     // cookie is available within the entire domain
		'cookie_domain' => '',    // cookie is available on current subdomain only
		'cookie_secure' => FALSE, // cookie is available on HTTP & HTTPS
		'cookie_httponly' => TRUE,// must be enabled to prevent Session Hijacking

		// other
		'gc_maxlifetime' => self::DEFAULT_FILE_LIFETIME,// 3 hours
		'cache_limiter' => NULL,  // (default "nocache", special value "\0")
		'cache_expire' => NULL,   // (default "180")
		'hash_function' => NULL,  // (default "0", means MD5)
		'hash_bits_per_character' => NULL, // (default "4")
	);

	/** @var IRequest */
	private $request;

	/** @var IResponse */
	private $response;

	/** @var \SessionHandlerInterface */
	private $handler;

	public function __construct(IRequest $request, IResponse $response)
	{
		$this->request = $request;
		$this->response = $response;
	}

	/**
	 * Starts and initializes session data.
	 * @throws Nette\InvalidStateException
	 * @return void
	 */
	public function start()
	{
		if (self::$started) {
			return;
		}

		$this->configure($this->options);

		$id = $this->request->getCookie(session_name());
		if (is_string($id) && preg_match('#^[0-9a-zA-Z,-]{22,128}\z#i', $id)) {
			session_id($id);
		} else {
			unset($_COOKIE[session_name()]);
		}

		try {
			// session_start returns FALSE on failure only sometimes
			Nette\Utils\Callback::invokeSafe('session_start', array(), function ($message) use (& $e) {
				$e = new Nette\InvalidStateException($message);
			});
		} catch (\Exception $e) {
		}

		Helpers::removeDuplicateCookies();
		if ($e) {
			@session_write_close(); // this is needed
			throw $e;
		}

		self::$started = TRUE;

		/* structure:
			__NF: BrowserKey, Data, Meta, Time
				DATA: section->variable = data
				META: section->variable = Timestamp, Browser
		*/
		$nf = & $_SESSION['__NF'];

		// regenerate empty session
		if (empty($nf['Time'])) {
			$nf['Time'] = time();
			$this->regenerated = TRUE;
		}

		// browser closing detection
		$browserKey = $this->request->getCookie('nette-browser');
		if (!is_string($browserKey) || !preg_match('#^[0-9a-z]{10}\z#', $browserKey)) {
			$browserKey = Nette\Utils\Random::generate();
		}
		$browserClosed = !isset($nf['B']) || $nf['B'] !== $browserKey;
		$nf['B'] = $browserKey;

		// resend cookie
		$this->sendCookie();

		// process meta metadata
		if (isset($nf['META'])) {
			$now = time();
			// expire section variables
			foreach ($nf['META'] as $section => $metadata) {
				if (is_array($metadata)) {
					foreach ($metadata as $variable => $value) {
						if ((!empty($value['B']) && $browserClosed) || (!empty($value['T']) && $now > $value['T'])) { // whenBrowserIsClosed || Time
							if ($variable === '') { // expire whole section
								unset($nf['META'][$section], $nf['DATA'][$section]);
								continue 2;
							}
							unset($nf['META'][$section][$variable], $nf['DATA'][$section][$variable]);
						}
					}
				}
			}
		}

		if ($this->regenerated) {
			$this->regenerated = FALSE;
			$this->regenerateId();
		}

		register_shutdown_function(array($this, 'clean'));
	}

	/**
	 * Has been session started?
	 * @return bool
	 */
	public function isStarted()
	{
		return (bool) self::$started;
	}

	/**
	 * Ends the current session and store session data.
	 * @return void
	 */
	public function close()
	{
		if (self::$started) {
			$this->clean();
			session_write_close();
			self::$started = FALSE;
		}
	}

	/**
	 * Destroys all data registered to a session.
	 * @return void
	 */
	public function destroy()
	{
		if (!self::$started) {
			throw new Nette\InvalidStateException('Session is not started.');
		}

		session_destroy();
		$_SESSION = NULL;
		self::$started = FALSE;
		if (!$this->response->isSent()) {
			$params = session_get_cookie_params();
			$this->response->deleteCookie(session_name(), $params['path'], $params['domain'], $params['secure']);
		}
	}

	/**
	 * Does session exists for the current request?
	 * @return bool
	 */
	public function exists()
	{
		return self::$started || $this->request->getCookie($this->getName()) !== NULL;
	}

	/**
	 * Regenerates the session ID.
	 * @throws Nette\InvalidStateException
	 * @return void
	 */
	public function regenerateId()
	{
		if (self::$started && !$this->regenerated) {
			if (headers_sent($file, $line)) {
				throw new Nette\InvalidStateException('Cannot regenerate session ID after HTTP headers have been sent' . ($file ? " (output started at $file:$line)." : '.'));
			}
			if (session_id() !== '') {
				session_regenerate_id(TRUE);
			}
			session_write_close();
			$backup = $_SESSION;
			session_start();
			$_SESSION = $backup;
			Helpers::removeDuplicateCookies();
		}
		$this->regenerated = TRUE;
	}

	/**
	 * Returns the current session ID. Don't make dependencies, can be changed for each request.
	 * @return string
	 */
	public function getId()
	{
		return session_id();
	}

	/**
	 * Sets the session name to a specified one.
	 * @param  string
	 * @return self
	 */
	public function setName($name)
	{
		if (!is_string($name) || !preg_match('#[^0-9.][^.]*\z#A', $name)) {
			throw new Nette\InvalidArgumentException('Session name must be a string and cannot contain dot.');
		}

		session_name($name);
		return $this->setOptions(array(
			'name' => $name,
		));
	}

	/**
	 * Gets the session name.
	 * @return string
	 */
	public function getName()
	{
		return isset($this->options['name']) ? $this->options['name'] : session_name();
	}

	/********************* sections management ****************d*g**/

	/**
	 * Returns specified session section.
	 * @param  string
	 * @param  string
	 * @return SessionSection
	 * @throws Nette\InvalidArgumentException
	 */
	public function getSection($section, $class = 'Nette\Http\SessionSection')
	{
		return new $class($this, $section);
	}

	/**
	 * Checks if a session section exist and is not empty.
	 * @param  string
	 * @return bool
	 */
	public function hasSection($section)
	{
		if ($this->exists() && !self::$started) {
			$this->start();
		}

		return !empty($_SESSION['__NF']['DATA'][$section]);
	}

	/**
	 * Iteration over all sections.
	 * @return \ArrayIterator
	 */
	public function getIterator()
	{
		if ($this->exists() && !self::$started) {
			$this->start();
		}

		if (isset($_SESSION['__NF']['DATA'])) {
			return new \ArrayIterator(array_keys($_SESSION['__NF']['DATA']));

		} else {
			return new \ArrayIterator;
		}
	}

	/**
	 * Cleans and minimizes meta structures. This method is called automatically on shutdown, do not call it directly.
	 * @internal
	 * @return void
	 */
	public function clean()
	{
		if (!self::$started || empty($_SESSION)) {
			return;
		}

		$nf = & $_SESSION['__NF'];
		if (isset($nf['META']) && is_array($nf['META'])) {
			foreach ($nf['META'] as $name => $foo) {
				if (empty($nf['META'][$name])) {
					unset($nf['META'][$name]);
				}
			}
		}

		if (empty($nf['META'])) {
			unset($nf['META']);
		}

		if (empty($nf['DATA'])) {
			unset($nf['DATA']);
		}
	}

	/********************* configuration ****************d*g**/

	/**
	 * Sets session options.
	 * @param  array
	 * @return self
	 * @throws Nette\NotSupportedException
	 * @throws Nette\InvalidStateException
	 */
	public function setOptions(array $options)
	{
		if (self::$started) {
			$this->configure($options);
		}
		$this->options = $options + $this->options;
		if (!empty($options['auto_start'])) {
			$this->start();
		}
		return $this;
	}

	/**
	 * Returns all session options.
	 * @return array
	 */
	public function getOptions()
	{
		return $this->options;
	}

	/**
	 * Configures session environment.
	 * @param  array
	 * @return void
	 */
	private function configure(array $config)
	{
		$special = array('cache_expire' => 1, 'cache_limiter' => 1, 'save_path' => 1, 'name' => 1);

		foreach ($config as $key => $value) {
			if (!strncmp($key, 'session.', 8)) { // back compatibility
				$key = substr($key, 8);
			}
			$key = strtolower(preg_replace('#(.)(?=[A-Z])#', '$1_', $key));

			if ($value === NULL || ini_get("session.$key") == $value) { // intentionally ==
				continue;

			} elseif (strncmp($key, 'cookie_', 7) === 0) {
				if (!isset($cookie)) {
					$cookie = session_get_cookie_params();
				}
				$cookie[substr($key, 7)] = $value;

			} else {
				if (defined('SID')) {
					throw new Nette\InvalidStateException("Unable to set 'session.$key' to value '$value' when session has been started" . ($this->started ? '.' : ' by session.auto_start or session_start().'));
				}
				if (isset($special[$key])) {
					$key = "session_$key";
					$key($value);

				} elseif (function_exists('ini_set')) {
					ini_set("session.$key", $value);

				} elseif (ini_get("session.$key") != $value) { // intentionally ==
					throw new Nette\NotSupportedException("Unable to set 'session.$key' to '$value' because function ini_set() is disabled.");
				}
			}
		}

		if (isset($cookie)) {
			session_set_cookie_params(
				$cookie['lifetime'], $cookie['path'], $cookie['domain'],
				$cookie['secure'], $cookie['httponly']
			);
			if (self::$started) {
				$this->sendCookie();
			}
		}

		if ($this->handler) {
			session_set_save_handler($this->handler);
		}
	}

	/**
	 * Sets the amount of time allowed between requests before the session will be terminated.
	 * @param  string|int|\DateTime  time, value 0 means "until the browser is closed"
	 * @return self
	 */
	public function setExpiration($time)
	{
		if (empty($time)) {
			return $this->setOptions(array(
				'gc_maxlifetime' => self::DEFAULT_FILE_LIFETIME,
				'cookie_lifetime' => 0,
			));

		} else {
			$time = Nette\Utils\DateTime::from($time)->format('U') - time();
			return $this->setOptions(array(
				'gc_maxlifetime' => $time,
				'cookie_lifetime' => $time,
			));
		}
	}

	/**
	 * Sets the session cookie parameters.
	 * @param  string  path
	 * @param  string  domain
	 * @param  bool    secure
	 * @return self
	 */
	public function setCookieParameters($path, $domain = NULL, $secure = NULL)
	{
		return $this->setOptions(array(
			'cookie_path' => $path,
			'cookie_domain' => $domain,
			'cookie_secure' => $secure,
		));
	}

	/**
	 * Returns the session cookie parameters.
	 * @return array  containing items: lifetime, path, domain, secure, httponly
	 */
	public function getCookieParameters()
	{
		return session_get_cookie_params();
	}

	/**
	 * Sets path of the directory used to save session data.
	 * @return self
	 */
	public function setSavePath($path)
	{
		return $this->setOptions(array(
			'save_path' => $path,
		));
	}

	/**
	 * Sets user session storage for PHP < 5.4. For PHP >= 5.4, use setHandler().
	 * @return self
	 */
	public function setStorage(ISessionStorage $storage)
	{
		if (self::$started) {
			throw new Nette\InvalidStateException('Unable to set storage when session has been started.');
		}
		session_set_save_handler(
			array($storage, 'open'), array($storage, 'close'), array($storage, 'read'),
			array($storage, 'write'), array($storage, 'remove'), array($storage, 'clean')
		);
		return $this;
	}

	/**
	 * Sets user session handler.
	 * @return self
	 */
	public function setHandler(\SessionHandlerInterface $handler)
	{
		if (self::$started) {
			throw new Nette\InvalidStateException('Unable to set handler when session has been started.');
		}
		$this->handler = $handler;
		return $this;
	}

	/**
	 * Sends the session cookies.
	 * @return void
	 */
	private function sendCookie()
	{
		if (!headers_sent() && ob_get_level() && ob_get_length()) {
			trigger_error('Possible problem: you are starting session while already having some data in output buffer. This may not work if the outputted data grows. Try starting the session earlier.', E_USER_NOTICE);
		}

		$cookie = $this->getCookieParameters();
		$this->response->setCookie(
			session_name(), session_id(),
			$cookie['lifetime'] ? $cookie['lifetime'] + time() : 0,
			$cookie['path'], $cookie['domain'], $cookie['secure'], $cookie['httponly']
		);
		$this->response->setCookie(
			'nette-browser', $_SESSION['__NF']['B'],
			Response::BROWSER, $cookie['path'], $cookie['domain']
		);
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;

/**
 * Session section.
 */
class SessionSection extends Nette\Object implements \IteratorAggregate, \ArrayAccess
{
	/** @var Session */
	private $session;

	/** @var string */
	private $name;

	/** @var array  session data storage */
	private $data;

	/** @var array  session metadata storage */
	private $meta = FALSE;

	/** @var bool */
	public $warnOnUndefined = FALSE;

	/**
	 * Do not call directly. Use Session::getSection().
	 */
	public function __construct(Session $session, $name)
	{
		if (!is_string($name)) {
			throw new Nette\InvalidArgumentException('Session namespace must be a string, ' . gettype($name) . ' given.');
		}

		$this->session = $session;
		$this->name = $name;
	}

	/**
	 * Do not call directly. Use Session::getNamespace().
	 */
	private function start()
	{
		if ($this->meta === FALSE) {
			$this->session->start();
			$this->data = & $_SESSION['__NF']['DATA'][$this->name];
			$this->meta = & $_SESSION['__NF']['META'][$this->name];
		}
	}

	/**
	 * Returns an iterator over all section variables.
	 * @return \ArrayIterator
	 */
	public function getIterator()
	{
		$this->start();
		if (isset($this->data)) {
			return new \ArrayIterator($this->data);
		} else {
			return new \ArrayIterator;
		}
	}

	/**
	 * Sets a variable in this session section.
	 * @param  string  name
	 * @param  mixed   value
	 * @return void
	 */
	public function __set($name, $value)
	{
		$this->start();
		$this->data[$name] = $value;
	}

	/**
	 * Gets a variable from this session section.
	 * @param  string    name
	 * @return mixed
	 */
	public function &__get($name)
	{
		$this->start();
		if ($this->warnOnUndefined && !array_key_exists($name, $this->data)) {
			trigger_error("The variable '$name' does not exist in session section", E_USER_NOTICE);
		}

		return $this->data[$name];
	}

	/**
	 * Determines whether a variable in this session section is set.
	 * @param  string    name
	 * @return bool
	 */
	public function __isset($name)
	{
		if ($this->session->exists()) {
			$this->start();
		}
		return isset($this->data[$name]);
	}

	/**
	 * Unsets a variable in this session section.
	 * @param  string    name
	 * @return void
	 */
	public function __unset($name)
	{
		$this->start();
		unset($this->data[$name], $this->meta[$name]);
	}

	/**
	 * Sets a variable in this session section.
	 * @param  string  name
	 * @param  mixed   value
	 * @return void
	 */
	public function offsetSet($name, $value)
	{
		$this->__set($name, $value);
	}

	/**
	 * Gets a variable from this session section.
	 * @param  string    name
	 * @return mixed
	 */
	public function offsetGet($name)
	{
		return $this->__get($name);
	}

	/**
	 * Determines whether a variable in this session section is set.
	 * @param  string    name
	 * @return bool
	 */
	public function offsetExists($name)
	{
		return $this->__isset($name);
	}

	/**
	 * Unsets a variable in this session section.
	 * @param  string    name
	 * @return void
	 */
	public function offsetUnset($name)
	{
		$this->__unset($name);
	}

	/**
	 * Sets the expiration of the section or specific variables.
	 * @param  string|int|\DateTime  time, value 0 means "until the browser is closed"
	 * @param  mixed   optional list of variables / single variable to expire
	 * @return self
	 */
	public function setExpiration($time, $variables = NULL)
	{
		$this->start();
		if (empty($time)) {
			$time = NULL;
			$whenBrowserIsClosed = TRUE;
		} else {
			$time = Nette\Utils\DateTime::from($time)->format('U');
			$max = (int) ini_get('session.gc_maxlifetime');
			if ($max !== 0 && ($time - time() > $max + 3)) { // 0 - unlimited in memcache handler, 3 - bulgarian constant
				trigger_error("The expiration time is greater than the session expiration $max seconds", E_USER_NOTICE);
			}
			$whenBrowserIsClosed = FALSE;
		}

		foreach (is_array($variables) ? $variables : array($variables) as $variable) {
			$this->meta[$variable]['T'] = $time;
			$this->meta[$variable]['B'] = $whenBrowserIsClosed;
		}
		return $this;
	}

	/**
	 * Removes the expiration from the section or specific variables.
	 * @param  mixed   optional list of variables / single variable to expire
	 * @return void
	 */
	public function removeExpiration($variables = NULL)
	{
		$this->start();
		foreach (is_array($variables) ? $variables : array($variables) as $variable) {
			unset($this->meta['']['T'], $this->meta['']['B']);
		}
	}

	/**
	 * Cancels the current session section.
	 * @return void
	 */
	public function remove()
	{
		$this->start();
		$this->data = NULL;
		$this->meta = NULL;
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;

/**
 * URI Syntax (RFC 3986).
 *
 * <pre>
 * scheme  user  password  host  port  basePath   relativeUrl
 *   |      |      |        |      |    |             |
 * /--\   /--\ /------\ /-------\ /--\/--\/----------------------------\
 * http://john:x0y17575@nette.org:8042/en/manual.php?name=param#fragment  <-- absoluteUrl
 *        \__________________________/\____________/^\________/^\______/
 *                     |                     |           |         |
 *                 authority               path        query    fragment
 * </pre>
 *
 * - authority:   [user[:password]@]host[:port]
 * - hostUrl:     http://user:password@nette.org:8042
 * - basePath:    /en/ (everything before relative URI not including the script name)
 * - baseUrl:     http://user:password@nette.org:8042/en/
 * - relativeUrl: manual.php
 *
 * @property   string $scheme
 * @property   string $user
 * @property   string $password
 * @property   string $host
 * @property   int $port
 * @property   string $path
 * @property   string $query
 * @property   string $fragment
 * @property-read string $absoluteUrl
 * @property-read string $authority
 * @property-read string $hostUrl
 * @property-read string $basePath
 * @property-read string $baseUrl
 * @property-read string $relativeUrl
 * @property-read array $queryParameters
 */
class Url extends Nette\Object
{
	/** @var array */
	public static $defaultPorts = array(
		'http' => 80,
		'https' => 443,
		'ftp' => 21,
		'news' => 119,
		'nntp' => 119,
	);

	/** @var string */
	private $scheme = '';

	/** @var string */
	private $user = '';

	/** @var string */
	private $password = '';

	/** @var string */
	private $host = '';

	/** @var int */
	private $port;

	/** @var string */
	private $path = '';

	/** @var array */
	private $query = array();

	/** @var string */
	private $fragment = '';

	/**
	 * @param  string|self
	 * @throws Nette\InvalidArgumentException if URL is malformed
	 */
	public function __construct($url = NULL)
	{
		if (is_string($url)) {
			$p = @parse_url($url); // @ - is escalated to exception
			if ($p === FALSE) {
				throw new Nette\InvalidArgumentException("Malformed or unsupported URI '$url'.");
			}

			$this->scheme = isset($p['scheme']) ? $p['scheme'] : '';
			$this->port = isset($p['port']) ? $p['port'] : NULL;
			$this->host = isset($p['host']) ? rawurldecode($p['host']) : '';
			$this->user = isset($p['user']) ? rawurldecode($p['user']) : '';
			$this->password = isset($p['pass']) ? rawurldecode($p['pass']) : '';
			$this->setPath(isset($p['path']) ? $p['path'] : '');
			$this->setQuery(isset($p['query']) ? $p['query'] : array());
			$this->fragment = isset($p['fragment']) ? rawurldecode($p['fragment']) : '';

		} elseif ($url instanceof self) {
			foreach ($this as $key => $val) {
				$this->$key = $url->$key;
			}
		}
	}

	/**
	 * Sets the scheme part of URI.
	 * @param  string
	 * @return self
	 */
	public function setScheme($value)
	{
		$this->scheme = (string) $value;
		return $this;
	}

	/**
	 * Returns the scheme part of URI.
	 * @return string
	 */
	public function getScheme()
	{
		return $this->scheme;
	}

	/**
	 * Sets the user name part of URI.
	 * @param  string
	 * @return self
	 */
	public function setUser($value)
	{
		$this->user = (string) $value;
		return $this;
	}

	/**
	 * Returns the user name part of URI.
	 * @return string
	 */
	public function getUser()
	{
		return $this->user;
	}

	/**
	 * Sets the password part of URI.
	 * @param  string
	 * @return self
	 */
	public function setPassword($value)
	{
		$this->password = (string) $value;
		return $this;
	}

	/**
	 * Returns the password part of URI.
	 * @return string
	 */
	public function getPassword()
	{
		return $this->password;
	}

	/**
	 * Sets the host part of URI.
	 * @param  string
	 * @return self
	 */
	public function setHost($value)
	{
		$this->host = (string) $value;
		$this->setPath($this->path);
		return $this;
	}

	/**
	 * Returns the host part of URI.
	 * @return string
	 */
	public function getHost()
	{
		return $this->host;
	}

	/**
	 * Sets the port part of URI.
	 * @param  int
	 * @return self
	 */
	public function setPort($value)
	{
		$this->port = (int) $value;
		return $this;
	}

	/**
	 * Returns the port part of URI.
	 * @return int
	 */
	public function getPort()
	{
		return $this->port
			? $this->port
			: (isset(self::$defaultPorts[$this->scheme]) ? self::$defaultPorts[$this->scheme] : NULL);
	}

	/**
	 * Sets the path part of URI.
	 * @param  string
	 * @return self
	 */
	public function setPath($value)
	{
		$this->path = (string) $value;
		if ($this->host && substr($this->path, 0, 1) !== '/') {
			$this->path = '/' . $this->path;
		}
		return $this;
	}

	/**
	 * Returns the path part of URI.
	 * @return string
	 */
	public function getPath()
	{
		return $this->path;
	}

	/**
	 * Sets the query part of URI.
	 * @param  string|array
	 * @return self
	 */
	public function setQuery($value)
	{
		$this->query = is_array($value) ? $value : self::parseQuery($value);
		return $this;
	}

	/**
	 * Appends the query part of URI.
	 * @param  string|array
	 * @return self
	 */
	public function appendQuery($value)
	{
		$this->query = is_array($value)
			? $value + $this->query
			: self::parseQuery($this->getQuery() . '&' . $value);
		return $this;
	}

	/**
	 * Returns the query part of URI.
	 * @return string
	 */
	public function getQuery()
	{
		if (PHP_VERSION_ID < 50400) {
			return str_replace('+', '%20', http_build_query($this->query, '', '&'));
		}
		return http_build_query($this->query, '', '&', PHP_QUERY_RFC3986);
	}

	/**
	 * @return array
	 */
	public function getQueryParameters()
	{
		return $this->query;
	}

	/**
	 * @param string
	 * @param mixed
	 * @return mixed
	 */
	public function getQueryParameter($name, $default = NULL)
	{
		return isset($this->query[$name]) ? $this->query[$name] : $default;
	}

	/**
	 * @param string
	 * @param mixed NULL unsets the parameter
	 * @return self
	 */
	public function setQueryParameter($name, $value)
	{
		$this->query[$name] = $value;
		return $this;
	}

	/**
	 * Sets the fragment part of URI.
	 * @param  string
	 * @return self
	 */
	public function setFragment($value)
	{
		$this->fragment = (string) $value;
		return $this;
	}

	/**
	 * Returns the fragment part of URI.
	 * @return string
	 */
	public function getFragment()
	{
		return $this->fragment;
	}

	/**
	 * Returns the entire URI including query string and fragment.
	 * @return string
	 */
	public function getAbsoluteUrl()
	{
		return $this->getHostUrl() . $this->path
			. (($tmp = $this->getQuery()) ? '?' . $tmp : '')
			. ($this->fragment === '' ? '' : '#' . $this->fragment);
	}

	/**
	 * Returns the [user[:pass]@]host[:port] part of URI.
	 * @return string
	 */
	public function getAuthority()
	{
		return $this->host === ''
			? ''
			: ($this->user !== '' && $this->scheme !== 'http' && $this->scheme !== 'https'
				? rawurlencode($this->user) . ($this->password === '' ? '' : ':' . rawurlencode($this->password)) . '@'
				: '')
			. $this->host
			. ($this->port && (!isset(self::$defaultPorts[$this->scheme]) || $this->port !== self::$defaultPorts[$this->scheme])
				? ':' . $this->port
				: '');
	}

	/**
	 * Returns the scheme and authority part of URI.
	 * @return string
	 */
	public function getHostUrl()
	{
		return ($this->scheme ? $this->scheme . ':' : '') . '//' . $this->getAuthority();
	}

	/**
	 * Returns the base-path.
	 * @return string
	 */
	public function getBasePath()
	{
		$pos = strrpos($this->path, '/');
		return $pos === FALSE ? '' : substr($this->path, 0, $pos + 1);
	}

	/**
	 * Returns the base-URI.
	 * @return string
	 */
	public function getBaseUrl()
	{
		return $this->getHostUrl() . $this->getBasePath();
	}

	/**
	 * Returns the relative-URI.
	 * @return string
	 */
	public function getRelativeUrl()
	{
		return (string) substr($this->getAbsoluteUrl(), strlen($this->getBaseUrl()));
	}

	/**
	 * URL comparison.
	 * @param  string|self
	 * @return bool
	 */
	public function isEqual($url)
	{
		$url = new self($url);
		$query = $url->query;
		ksort($query);
		$query2 = $this->query;
		ksort($query2);
		$http = in_array($this->scheme, array('http', 'https'), TRUE);
		return $url->scheme === $this->scheme
			&& !strcasecmp($url->host, $this->host)
			&& $url->getPort() === $this->getPort()
			&& ($http || $url->user === $this->user)
			&& ($http || $url->password === $this->password)
			&& self::unescape($url->path, '%/') === self::unescape($this->path, '%/')
			&& $query === $query2
			&& $url->fragment === $this->fragment;
	}

	/**
	 * Transforms URL to canonical form.
	 * @return self
	 */
	public function canonicalize()
	{
		$this->path = preg_replace_callback(
			'#[^!$&\'()*+,/:;=@%]+#',
			function ($m) { return rawurlencode($m[0]); },
			self::unescape($this->path, '%/')
		);
		$this->host = strtolower($this->host);
		return $this;
	}

	/**
	 * @return string
	 */
	public function __toString()
	{
		return $this->getAbsoluteUrl();
	}

	/**
	 * Similar to rawurldecode, but preserves reserved chars encoded.
	 * @param  string to decode
	 * @param  string reserved characters
	 * @return string
	 */
	public static function unescape($s, $reserved = '%;/?:@&=+$,')
	{
		// reserved (@see RFC 2396) = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
		// within a path segment, the characters "/", ";", "=", "?" are reserved
		// within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", "$" are reserved.
		if ($reserved !== '') {
			$s = preg_replace_callback(
				'#%(' . substr(chunk_split(bin2hex($reserved), 2, '|'), 0, -1) . ')#i',
				function ($m) { return '%25' . strtoupper($m[1]); },
				$s
			);
		}
		return rawurldecode($s);
	}

	/**
	 * Parses query string.
	 * @return array
	 */
	public static function parseQuery($s)
	{
		parse_str($s, $res);
		if (get_magic_quotes_gpc()) { // for PHP 5.3
			$res = Helpers::stripSlashes($res);
		}
		return $res;
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

/**
 * Extended HTTP URL.
 *
 * <pre>
 * http://nette.org/admin/script.php/pathinfo/?name=param#fragment
 *                 \_______________/\________/
 *                        |              |
 *                   scriptPath       pathInfo
 * </pre>
 *
 * - scriptPath:  /admin/script.php (or simply /admin/ when script is directory index)
 * - pathInfo:    /pathinfo/ (additional path information)
 *
 * @property   string $scriptPath
 * @property-read string $pathInfo
 */
class UrlScript extends Url
{
	/** @var string */
	private $scriptPath = '/';

	/**
	 * Sets the script-path part of URI.
	 * @param  string
	 * @return self
	 */
	public function setScriptPath($value)
	{
		$this->scriptPath = (string) $value;
		return $this;
	}

	/**
	 * Returns the script-path part of URI.
	 * @return string
	 */
	public function getScriptPath()
	{
		return $this->scriptPath;
	}

	/**
	 * Returns the base-path.
	 * @return string
	 */
	public function getBasePath()
	{
		$pos = strrpos($this->scriptPath, '/');
		return $pos === FALSE ? '' : substr($this->getPath(), 0, $pos + 1);
	}

	/**
	 * Returns the additional path information.
	 * @return string
	 */
	public function getPathInfo()
	{
		return (string) substr($this->getPath(), strlen($this->scriptPath));
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Http;

use Nette;
use Nette\Security\IIdentity;

/**
 * Session storage for user object.
 */
class UserStorage extends Nette\Object implements Nette\Security\IUserStorage
{
	/** @var string */
	private $namespace = '';

	/** @var Session */
	private $sessionHandler;

	/** @var SessionSection */
	private $sessionSection;

	public function __construct(Session $sessionHandler)
	{
		$this->sessionHandler = $sessionHandler;
	}

	/**
	 * Sets the authenticated status of this user.
	 * @param  bool
	 * @return self
	 */
	public function setAuthenticated($state)
	{
		$section = $this->getSessionSection(TRUE);
		$section->authenticated = (bool) $state;

		// Session Fixation defence
		$this->sessionHandler->regenerateId();

		if ($state) {
			$section->reason = NULL;
			$section->authTime = time(); // informative value

		} else {
			$section->reason = self::MANUAL;
			$section->authTime = NULL;
		}
		return $this;
	}

	/**
	 * Is this user authenticated?
	 * @return bool
	 */
	public function isAuthenticated()
	{
		$session = $this->getSessionSection(FALSE);
		return $session && $session->authenticated;
	}

	/**
	 * Sets the user identity.
	 * @return self
	 */
	public function setIdentity(IIdentity $identity = NULL)
	{
		$this->getSessionSection(TRUE)->identity = $identity;
		return $this;
	}

	/**
	 * Returns current user identity, if any.
	 * @return Nette\Security\IIdentity|NULL
	 */
	public function getIdentity()
	{
		$session = $this->getSessionSection(FALSE);
		return $session ? $session->identity : NULL;
	}

	/**
	 * Changes namespace; allows more users to share a session.
	 * @param  string
	 * @return self
	 */
	public function setNamespace($namespace)
	{
		if ($this->namespace !== $namespace) {
			$this->namespace = (string) $namespace;
			$this->sessionSection = NULL;
		}
		return $this;
	}

	/**
	 * Returns current namespace.
	 * @return string
	 */
	public function getNamespace()
	{
		return $this->namespace;
	}

	/**
	 * Enables log out after inactivity.
	 * @param  string|int|\DateTime Number of seconds or timestamp
	 * @param  int Log out when the browser is closed | Clear the identity from persistent storage?
	 * @return self
	 */
	public function setExpiration($time, $flags = 0)
	{
		$section = $this->getSessionSection(TRUE);
		if ($time) {
			$time = Nette\Utils\DateTime::from($time)->format('U');
			$section->expireTime = $time;
			$section->expireDelta = $time - time();

		} else {
			unset($section->expireTime, $section->expireDelta);
		}

		$section->expireIdentity = (bool) ($flags & self::CLEAR_IDENTITY);
		$section->expireBrowser = (bool) ($flags & self::BROWSER_CLOSED);
		$section->browserCheck = TRUE;
		$section->setExpiration(0, 'browserCheck');
		$section->setExpiration($time, 'foo'); // time check
		return $this;
	}

	/**
	 * Why was user logged out?
	 * @return int|NULL
	 */
	public function getLogoutReason()
	{
		$session = $this->getSessionSection(FALSE);
		return $session ? $session->reason : NULL;
	}

	/**
	 * Returns and initializes $this->sessionSection.
	 * @return SessionSection
	 */
	protected function getSessionSection($need)
	{
		if ($this->sessionSection !== NULL) {
			return $this->sessionSection;
		}

		if (!$need && !$this->sessionHandler->exists()) {
			return NULL;
		}

		$this->sessionSection = $section = $this->sessionHandler->getSection('Nette.Http.UserStorage/' . $this->namespace);

		if (!$section->identity instanceof IIdentity || !is_bool($section->authenticated)) {
			$section->remove();
		}

		if ($section->authenticated && $section->expireBrowser && !$section->browserCheck) { // check if browser was closed?
			$section->reason = self::BROWSER_CLOSED;
			$section->authenticated = FALSE;
			if ($section->expireIdentity) {
				unset($section->identity);
			}
		}

		if ($section->authenticated && $section->expireDelta > 0) { // check time expiration
			if ($section->expireTime < time()) {
				$section->reason = self::INACTIVITY;
				$section->authenticated = FALSE;
				if ($section->expireIdentity) {
					unset($section->identity);
				}
			}
			$section->expireTime = time() + $section->expireDelta; // sliding expiration
		}

		if (!$section->authenticated) {
			unset($section->expireTime, $section->expireDelta, $section->expireIdentity,
				$section->expireBrowser, $section->browserCheck, $section->authTime);
		}

		return $this->sessionSection;
	}

}


nette/mail

description: Nette Mail: Sending E-mails

ext-fileinfo: to detect type of attached files


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Bridges\MailDI;

use Nette;

/**
 * Mail extension for Nette DI.
 */
class MailExtension extends Nette\DI\CompilerExtension
{

	public $defaults = array(
		'smtp' => FALSE,
		'host' => NULL,
		'port' => NULL,
		'username' => NULL,
		'password' => NULL,
		'secure' => NULL,
		'timeout' => NULL,
	);

	public function loadConfiguration()
	{
		$container = $this->getContainerBuilder();
		$config = $this->validateConfig($this->defaults);

		$mailer = $container->addDefinition($this->prefix('mailer'))
			->setClass('Nette\Mail\IMailer');

		if (empty($config['smtp'])) {
			$mailer->setFactory('Nette\Mail\SendmailMailer');
		} else {
			$mailer->setFactory('Nette\Mail\SmtpMailer', array($config));
		}

		if ($this->name === 'mail') {
			$container->addAlias('nette.mailer', $this->prefix('mailer'));
		}
	}

}


code:
<?php

/**
 * This file is part of the Nette Framework (https://nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Nette\Mail;

/**
 * Mailer interface.
 */
interface IMailer
{

	/**
	 * Sends email.
	 * @return void
	 * @throws SendException
	 */
	function send(Message $mail);

}