Комментарии 15
        if ($link->load(array('code="'.$code.'"', 'link=?'))) {
            $link->load(array('code="'.$code.'"', 'link=?'));


Тут вторая строка лишняя. И нет ли случайно места для SQL injection?
Нет, не лишняя — в любом случае нужно загрузить в $link данные, в if'е мы их только проверяем (я могу быть не прав)
SQL тут нет — в FatFree встроен PDO, можете попробовать в демке
компилятору всё равно в IF она или нет. Метод выполнился. Если он что то хотел сделать (по доке), он сделал. Если что-то вернуть надо было — вернул (true допустим).
На счёт injection не уверен, но допустим что будет если свалится $code = '" or 1=1 or code="';?
Набор символов, кмк, лучше расширить. У меня сделано так:
$symbols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$symbols.= 'abcdefghijklmnopqrstuvwxyz';
$symbols.= '0123456789'; 

Несколько строк — для улучшения читаемости набора.

Можно ещё проще и читаемее =)


$symbols = [...range(48, 57), ...range(65, 90), ...range(97, 122)];

Правда чуть менее очевидно… Но зато не выглядит как извращение с перечислением всего возможного.

Ваш способ был в первой итерации, но пришли к тому, что я указал.
Очевидность лучше неочевидности. ¯\_(ツ)_/¯
Настоятельно рекомендую даже в таком маленьком деле делать валидацию ввода и на стороне сервера, с выводом соответствующих ошибок, не стоит полагаться на добавление аттрибута required и типа type=«url» к полю ввода
Не понял бизнес логику приложения, сделал ссылку a.nikonovs.ru/L89O, переходя по ней он редиректит с кодом 302 на то значение которое было введено при создании ссылки, на мой взгляд это абсолютно лишнее действие, хотелось понять зачем оно было нужно
Ну, так как $f3->reroute($link->link); определяет что ' OR 1=1 INTO OUTFILE /var/www/html/public_html/ — это не ссылка (без http://), то редиректит на внутреннюю страницу. По этому же принципу работает
<a href="xxx"></a>
— без http(s):// он считает это внутренней ссылкой. В нормальном случае — он сразу редиректит.

А так как ваша SQL Injection вызывает ошибку — вы получаете заглушку. Я изменил
$f3->set('DEBUG', 1);
на

$f3->set('DEBUG', 0);

$f3->set('ONERROR', function () {
    echo '<h1>Some Error Occurred!</h1> Please contact me at comments at <a href="https://a.nikonovs.ru/V2B9">this article</a>'; 
});
Нужно ведь в продакшене изменять DEBUG на 0. У меня на этом хостинге не только демо ведь висит ;)
На мой взгляд тут есть проблема:
определение пользовательская ссылка или внутренняя ссылка происходит по такому символическому признаку как сам текст ссылки, наверно лучше было бы использовать какой то отдельный путь для сервиса коротких ссылок, например:
a.nikonovs.ru/a/сама_короткая_ссылка
ну или на крайний случай какой то спецсимвол, например:
a.nikonovs.ru/~2HFG
или наоборот считать все короткими ссылками кроме путей типа
index.php?[всякие параметры]
Просто чтобы в плане логики это было более явно (однозначней), а то такой сервис просто не будет работать с URI ссылками, типа магнет ссылок как на торрент трекерах, да или даже ссылки типа phpstorm:[имя файла], для открытия файла сразу в нужной IDE, стоит отметить что и магнет ссылки и остальные URI ссылки отлично валидируются типом «url» для инпута, так что их поддержка просто напрашивается.
При том что текст сохранился в БД означает что эта инъекция не прошла, и тут нужно снова вернуться к вопросу валидации пользовательского ввода.
Я искренне надеюсь что параметр DEBUG 0 у вас задается не для всего хостинга сразу))
В остальном я желаю удачи во всех начинаниях
Конечно не Laravel и тому подобные — сегодня обойдёмся 65-ю килобайтами FatFreeFramework

Какой смысл изучать никому не известный фреймворк, который Yet Another?
Почему не использовать компоненты симфони? Опыт работы с ними намного больше пригодится в будущем, чем "очередной фреймворк".
Про размер смешно — это же не фронт.

Список роутов можно вынести в отдельный файл, например в /app/routes.ini

[routes]
GET / 	= controllers\lnk->home
GET /newLink 	= controllers\lnk->newlink
POST /newLink	= controllers\lnk->newlink
GET /@code = controllers\lnk->show


подключить его в index.php через

$f3->config('app/routes.ini');


и потом в отдельном классе реализовать всю функциональность

Namespace controllers;
class lnk {

	function beforeroute($f3) {
	}

	function afterroute($f3) {
		$layout = $f3->get( "default_layout" );
		echo \Template::instance()->render( $layout );
        }

	function home( $f3, $args ){
                ...
		$f3->set("inc", "home.htm");
	}

	function newlink( $f3, $args ){
                ...
		$f3->set("inc", "newLink.htm");
	}
}


По-моему так несколько аккуратнее. Или это уже входит в понятие «жир» Ж)?
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.