Как вы можете видеть, люди предлагают вам максимально использовать подготовленные заявления. Это не так, но когда ваш запрос выполняется всего один раз за процесс, будет небольшое снижение производительности.
Я столкнулся с этой проблемой, но я думаю, что решил ее в очень сложном пути - как хакеры используют, чтобы избежать использования кавычек. Я использовал это в сочетании с эмулированными подготовленными заявлениями. Я использую его, чтобы предотвратить все возможные типы инъекций SQL. Так, например, запрос: Будет: или Hex - идеальный выход. В комментариях было некоторое обсуждение, поэтому я, наконец, хочу дать понять. Эти два подхода очень похожи, но в некоторых отношениях они немного различаются: Префикс ** 0x ** может использоваться только для столбцов данных, таких как char, varchar, text, block, binary, и т. д. Кроме того, его использование немного сложно, если вы собираетесь вставить пустую строку. Вам придется полностью заменить его на UNHEX () работает в любом столбце; вам не нужно беспокоиться о пустой строке. Обратите внимание, что этот шестиугольный метод часто используется как атака SQL-инъекции, где целые числа точно так же, как и строки Например, если вы просто делаете что-то вроде этого: атака может очень легко ввести вас . Рассмотрим следующий введенный код, возвращенный из вашего скрипта: SELECT ... WHERE id = -1 union all select table_name from information_schema.tables и теперь просто извлеките структуру таблицы: SELECT ... WHERE id = -1 union all select column_name from information_schema.column где table_name = 0x61727469636c65 И тогда просто выберите нужные данные. Разве это не круто? Но если кодер инъекционного сайта будет шестнадцатеричным, инъекция не будет возможна, потому что запрос будет выглядеть следующим образом: Мой подход:
sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);
mysql_hex_string()
, в PHP вы можете использовать bin2hex()
. Не беспокойтесь о том, что экранированная строка будет иметь размер в 2 раза по сравнению с исходной длиной, потому что даже если вы используете mysql_real_escape_string
, PHP должен выделять одну и ту же емкость ((2*input_length)+1)
, что то же самое. 0x
или использовать функцию MySQL UNHEX
. SELECT password FROM users WHERE name = 'root'
SELECT password FROM users WHERE name = 0x726f6f74
SELECT password FROM users WHERE name = UNHEX('726f6f74')
Разница между функцией UNHEX и префиксом 0x
''
, или вы получите сообщение об ошибке. Hex-методы часто используются в качестве атак
mysql_real_escape_string
. Тогда вы можете избежать использования кавычек. "SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])
SELECT ... WHERE id = UNHEX('2d312075...3635')
Вопреки то, что другие говорят, перегружаясь типом возврата, возможно, и сделаны некоторыми современными языками. Обычное возражение состоит в том, что в коде как [1 152]
int func();
string func();
int main() { func(); }
Вы не можете сказать, которым func()
называется. Это может быть разрешено несколькими способами:
int main() { (string)func(); }
. Два из языков I регулярно ( ab) используют перегрузку типом возврата: Perl и Haskell. Позвольте мне описать то, что они делают.
В [1 179] Perl, существует фундаментальное различие между [1 140] скаляр и список контекст (и другие, но мы притворимся, что существует два). Каждая встроенная функция в Perl может сделать разные вещи в зависимости от контекст , в котором это называют. Например, join
оператор вызывает контекст списка (на вещи, к которой присоединяются), в то время как scalar
оператор вызывает скалярный контекст, поэтому сравните:
print join " ", localtime(); # printed "58 11 2 14 0 109 3 13 0" for me right now
print scalar localtime(); # printed "Wed Jan 14 02:12:44 2009" for me right now.
Каждый оператор в Perl делает что-то в скалярном контексте и что-то в контексте списка, и они могут отличаться, как проиллюстрировано. (Это не только для случайных операторов как [1 112]. При использовании массива @a
в контексте списка это возвращает массив, в то время как в скалярном контексте, это возвращает число элементов. Так, например print @a
распечатывает элементы, в то время как print 0+@a
печать размер.), Кроме того, каждый оператор может сила контекст, например, дополнение +
контекст скаляра сил. Каждая запись в [1 117] документы это. Например, вот часть записи для [1 118]:
В контексте списка, возвраты (возможно пустой) список расширений имени файла на значении [1 119], таких как стандартная оболочка Unix
/bin/csh
сделал бы. В скалярном контексте шарик выполняет итерации посредством таких расширений имени файла, возвращаясь undef, когда список исчерпывается.
Теперь, каково отношение между списком и скалярным контекстом? Ну, man perlfunc
говорит
, Помнят следующее важное правило: нет никакого правила, которое связывает поведение выражения в контексте списка к его поведению в скалярном контексте, или наоборот. Это могло бы сделать две полностью разных вещи. Каждый оператор и функция решают, какой вид значения было бы самым уместным возвратить в скалярном контексте. Некоторые операторы возвращают длину списка, который был бы возвращен в контексте списка. Некоторые операторы возвращают первое значение в списке. Некоторые операторы возвращают последнее значение в списке. Некоторые операторы возвращают количество успешных операций. В целом они делают то, что Вы хотите, если Вы не хотите непротиворечивости.
, таким образом, это не простой вопрос наличия единственной функции, и затем Вы делаете простое преобразование в конце. На самом деле я выбрал localtime
пример по этой причине.
Это не просто созданные-ins, которые имеют это поведение. Любой пользователь может определить такую функцию с помощью [1 123], который позволяет Вам различать список, скаляр и пустой контекст. Так, например, можно решить ничего не сделать, если Вас звонят в пустом контексте.
Теперь, можно жаловаться, что это не верно перегрузка возвращаемым значением, потому что у Вас только есть одна функция, которой говорят контекст, это призвано и затем действует на ту информацию. Однако это явно эквивалентно (и аналогично тому, как Perl не позволяет обычную перегрузку буквально, но функция может просто исследовать свои аргументы). Кроме того, это приятно разрешает неоднозначную ситуацию, упомянутую в начале этого ответа. Perl не жалуется, что не знает который метод звонить; это просто называет его. Все, что это должно сделать, выяснить, какой контекст функция была призвана, который всегда возможен:
sub func {
if( not defined wantarray ) {
print "void\n";
} elsif( wantarray ) {
print "list\n";
} else {
print "scalar\n";
}
}
func(); # prints "void"
() = func(); # prints "list"
0+func(); # prints "scalar"
(Примечание: Я могу иногда говорить оператор Perl, когда я имею в виду функцию. Это не крайне важно для этого обсуждения.)
Haskell проявляет другой подход, а именно, для не имения побочных эффектов. Это также имеет сильную систему типов, и таким образом, можно записать код как следующее:
main = do n <- readLn
print (sqrt n) -- note that this is aligned below the n, if you care to run this
Этот код читает число с плавающей точкой из стандартного входа и печатает его квадратный корень. Но что удивительно об этом? Ну, тип [1 124] readLn :: Read a => IO a
. То, что это означает, - то, что для любого типа, который может быть Read
(официально, каждый тип, который является экземпляром Read
класс типа), readLn
может считать его. Как Haskell знал, что я хотел считать число с плавающей точкой? Ну, тип [1 129] sqrt :: Floating a => a -> a
, который по существу означает, что sqrt
может только принять числа с плавающей точкой как исходные данные, и таким образом, Haskell вывел то, что я хотел.
, Что происходит, когда Haskell не может вывести то, что я хочу? Ну, там несколько возможностей. Если я не буду использовать возвращаемое значение вообще, Haskell просто не вызовет функцию во-первых. Однако, если я делаю , используют возвращаемое значение, тогда Haskell будет жаловаться, что оно не может вывести тип:
main = do n <- readLn
print n
-- this program results in a compile-time error "Unresolved top-level overloading"
я могу разрешить неоднозначность путем определения типа, который я хочу:
main = do n <- readLn
print (n::Int)
-- this compiles (and does what I want)
Так или иначе, то, что означает это целое обсуждение, - то, что перегрузка возвращаемым значением возможна и сделана, который отвечает на часть Вашего вопроса.
другая часть Вашего вопроса - то, почему больше языков не делает этого. Я позволю другим ответить на это. Однако несколько комментариев: принципиальная причина состоит, вероятно в том, что возможность для беспорядка действительно больше здесь, чем в перегрузке типом аргумента. Можно также посмотреть на объяснения с отдельных языков:
Ada: "Могло бы казаться, что самое простое правило разрешения перегрузки состоит в том, чтобы использовать все - всю информацию от максимально широкого контекста - для разрешения перегруженной ссылки. Это правило может быть простым, но это не полезно. Это требует, чтобы читатель просканировал произвольно большие части текста и сделал произвольно сложные выводы (такие как (g) выше). Мы полагаем, что лучшее правило является тем, которое делает явным задача, которую должны выполнить читатель или компилятор, и это делает эту задачу максимально естественной для читателя".
C++ (подраздел 7.4.1of Bjarne Stroustrup "Язык Программирования на C++"): "Возвратитесь, типы не рассматривают в разрешении перегрузки. Причина состоит в том, чтобы сохранить разрешение для отдельного оператора или вызова функции независимым от контекста. Рассмотрите:
float sqrt(float);
double sqrt(double);
void f(double da, float fla)
{
float fl = sqrt(da); // call sqrt(double)
double d = sqrt(da); // call sqrt(double)
fl = sqrt(fla); // call sqrt(float)
d = sqrt(fla); // call sqrt(float)
}
, Если бы тип возврата был принят во внимание, больше не было бы возможно посмотреть на вызов [1 132] в изоляции и определить, какая функция была вызвана". (Обратите внимание для сравнения, что в Haskell нет никаких неявны преобразования.)
Java ( Спецификация языка 9.4.1 Java): "Один из унаследованных методов должен, должен быть тип возврата, substitutable для любого другого унаследованного метода; иначе ошибка времени компиляции происходит". (Да, я знаю, что это не дает объяснение. Я уверен, что объяснение дано Gosling на "Языке программирования Java". Возможно, у кого-то есть копия? Я держал пари, что это - "принцип наименьшего количества удивления" в сущности.) Однако забавный факт о Java: JVM позволяет перегрузка возвращаемым значением! Это используется, например, в [1 136] Scala, и может быть получено доступ непосредственно через Java также путем игры вокруг с внутренностями.
пз. Как заключительное примечание, на самом деле возможно перегрузиться возвращаемым значением в C++ с приемом. Свидетель:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
Большинство статических языков также теперь поддерживает дженерики, которые решили бы Вашу проблему. Как указано прежде, не имея параметра diffs, нет способа знать который звонить. Таким образом, если Вы хотите сделать это, просто используйте дженерики и прекратите дело.
В haskell это возможно даже при том, что это не имеет перегрузки функции. Haskell использует классы типа. В программе Вы видели:
class Example a where
example :: Integer -> a
instance Example Integer where -- example is now implemented for Integer
example :: Integer -> Integer
example i = i * 10
сама Перегрузка функции не так популярна. Главным образом языки, которые я видел с ним, являются C++, возможно, Java и/или C#. На всех динамических языках это - стенография для:
define example:i
↑i type route:
Integer = [↑i & 0xff]
String = [↑i upper]
def example(i):
if isinstance(i, int):
return i & 0xff
elif isinstance(i, str):
return i.upper()
Поэтому нет никакого большого количества точки в нем. Большинству людей не интересно, может ли язык помочь Вам отбросить одну строку на то, где когда-либо Вы используете его.
Сопоставление с образцом несколько подобно перегрузке функции, и я иногда предполагаю работу так же. Это не распространено хотя, потому что это полезно только для немногих программ и хитро для реализации на большинстве языков.
Вы видите, что существует бесконечно много других лучших более легких к реализации функций для реализации на язык, включая:
Украсть C++, конкретный ответ от другого очень похожего вопроса (простофиля?):
<час>Функциональные типы возврата не играют роли в разрешении перегрузки просто, потому что Stroustrup (я принимаю с входом от других архитекторов C++), требуемое разрешение перегрузки, чтобы быть 'независимым контекстом'. См. 7.4.1 - "Перегрузка и Тип Возврата" с "Языка Программирования на C++, Третий Выпуск".
причина состоит в том, чтобы сохранить разрешение для отдельного оператора или вызова функции независимым от контекста.
Они хотели, чтобы он базировался только о том, как перегрузку назвали - не, как результат использовался (если это использовалось вообще). Действительно, много функций вызваны, не используя результат, или результат использовался бы в качестве части большего выражения. Один фактор, что я уверен, играл роль, когда они решили, что это было то, что, если бы тип возврата был частью разрешения, было бы много вызовов к перегруженным функциям, которые должны были бы быть разрешены со сложными правилами или должны будут иметь бросок компилятора ошибка, что вызов был неоднозначен.
И, Господь знает, разрешение перегрузки C++ достаточно сложно как есть...
На таком языке, как был бы Вы разрешать следующее:
f(g(x))
, если f
имел перегрузки void f(int)
и void f(string)
и g
, имел перегрузки int g(int)
и string g(int)
? Вам был бы нужен некоторый disambiguator.
я думаю ситуации, где Вам, возможно, понадобилось бы, это будет лучше подаваться путем выбора нового названия функции.
Если функции были перегружены типом возврата, и у Вас были эти две перегрузки
int func();
string func();
нет никакого способа, которым мог выяснить компилятор, какую из тех двух функций для призыва наблюдения вызова как это
void main()
{
func();
}
поэтому разработчики языка часто запрещают перегрузке возвращаемого значения.
Некоторые языки (такие как MSIL), однако, делают , позволяют перегружаться типом возврата. Они также сталкиваются с вышеупомянутой трудностью, конечно, но у них есть обходные решения, для которых необходимо будет консультироваться с их документацией.