Различие между объявлением переменных прежде или в цикле?

Я использую три разных способа предотвращения уязвимости моего веб-приложения для SQL-инъекции.

  1. Использование mysql_real_escape_string(), которое является предопределенной функцией в PHP , и этот код добавляет обратную косую черту к следующим символам: \x00, \n, \r, \, ', " и \x1a. Передайте входные значения в качестве параметров, чтобы свести к минимуму вероятность внедрения SQL.
  2. Самый продвинутый способ - использовать PDO.

Надеюсь, это поможет вам.

Рассмотрим следующий запрос:

$iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

mysql_real_escape_string () здесь не защитит. Если вы используете одиночные кавычки ('') вокруг ваших переменных внутри вашего запроса, это то, что защищает вас от этого. Ниже приведено ниже решение:

$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

В этом вопросе есть хорошие ответы.

Я предлагаю , наилучшим вариантом является использование PDO.

Изменить:

mysql_real_escape_string() устарел с PHP 5.5.0. Используйте либо mysqli, либо PDO.

Альтернативой mysql_real_escape_string () является

string mysqli_real_escape_string ( mysqli $link , string $escapestr )

Пример:

$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");

307
задан GedankenNebel 5 March 2017 в 23:52
поделиться

15 ответов

Который лучше, или b?

С точки зрения производительности, необходимо было бы измерить его. (И по-моему, если можно измерить различие, компилятор не очень хорош).

С точки зрения обслуживания, b лучше. Объявите и инициализируйте переменные в том же месте в самом узком возможном объеме. Не покидайте зияющую дыру между объявлением и инициализацией, и не загрязняйте пространства имен, Вы не должны.

250
ответ дан Sunil Kanzar 23 November 2019 в 01:18
поделиться

Даже если я буду знать, что мой компилятор достаточно умен, я не буду любить полагаться на него и буду использовать a) вариант.

b) вариант имеет смысл мне, только если отчаянно необходимо сделать intermediateResult недоступный после тела цикла. Но я не могу вообразить такое отчаянное положение, так или иначе....

РЕДАКТИРОВАНИЕ: Jon Skeet сделал очень правильное замечание, показав, что объявление переменной в цикле может иметь фактическое семантическое значение.

-1
ответ дан Abgan 23 November 2019 в 01:18
поделиться

Я думаю, что это зависит от компилятора и твердо дать общий ответ.

3
ответ дан SquidScareMe 23 November 2019 в 01:18
поделиться

Коллега предпочитает первую форму, говоря, что это - оптимизация, предпочитая снова использовать объявление.

я предпочитаю второй (и попытайтесь убедить моего коллегу!;-)), считав, что:

  • Это уменьшает объем переменных туда, где они необходимы, который является хорошей вещью.
  • Java оптимизирует достаточно, чтобы не иметь никакого значительного значения в производительности. IIRC, возможно, вторая форма еще быстрее.

Так или иначе, это падает в категории преждевременной оптимизации, которые полагаются в качестве компилятора и/или JVM.

5
ответ дан PhiLho 23 November 2019 в 01:18
поделиться

Хорошо я выполнил Ваш A и примеры B 20 раз каждый, цикличное выполнение 100 миллионов раз. (JVM - 1.5.0)

А: среднее время выполнения:.074 секунд

B: среднее время выполнения:.067 секунд

К моему удивлению B были немного быстрее. С такой скоростью, как компьютеры являются теперь его твердым, чтобы сказать, могли ли Вы точно измерить это. Я кодировал бы его путь также, но я скажу, что это действительно не имеет значения.

210
ответ дан Mark 23 November 2019 в 01:18
поделиться

Это зависит от языка и точного использования. Например, в C# 1 это не имело никакого значения. В C# 2, если локальная переменная получена анонимным методом (или лямбда-выражение в C# 3) она может сделать очень signficant различие.

Пример:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        List<Action> actions = new List<Action>();

        int outer;
        for (int i=0; i < 10; i++)
        {
            outer = i;
            int inner = i;
            actions.Add(() => Console.WriteLine("Inner={0}, Outer={1}", inner, outer));
        }

        foreach (Action action in actions)
        {
            action();
        }
    }
}

Вывод:

Inner=0, Outer=9
Inner=1, Outer=9
Inner=2, Outer=9
Inner=3, Outer=9
Inner=4, Outer=9
Inner=5, Outer=9
Inner=6, Outer=9
Inner=7, Outer=9
Inner=8, Outer=9
Inner=9, Outer=9

различие - то, что все действия получают тот же outer переменная, но у каждого есть ее собственное отдельное inner переменная.

66
ответ дан Jon Skeet 23 November 2019 в 01:18
поделиться

Это - глюк в VB.NET. Результат Visual Basic не повторно инициализирует переменную в этом примере:

For i as Integer = 1 to 100
    Dim j as Integer
    Console.WriteLine(j)
    j = i
Next

' Output: 0 1 2 3 4...

Это распечатает 0 в первый раз (переменные Visual Basic имеют значения по умолчанию, когда объявлено!), но i каждый раз после этого.

, Если Вы добавляете = 0, тем не менее, Вы получаете то, что Вы могли бы ожидать:

For i as Integer = 1 to 100
    Dim j as Integer = 0
    Console.WriteLine(j)
    j = i
Next

'Output: 0 0 0 0 0...
24
ответ дан Peter Mortensen 23 November 2019 в 01:18
поделиться

Это является языковозависимым - IIRC C# оптимизирует это, таким образом, нет никакого различия, но JavaScript (например), сделает целую хижину выделения памяти каждый раз.

12
ответ дан Peter Mortensen 23 November 2019 в 01:18
поделиться

По-моему, b является лучшей структурой. В a слоняется поблизости последнее значение intermediateResult после того, как Ваш цикл закончен.

Редактирование: Это не имеет большое значение с типами значения, но ссылочные типы могут быть несколько тяжелыми. Лично, мне нравится, когда переменные разыменовываются как можно скорее для очистки, и b делает это для Вас,

6
ответ дан Powerlord 23 November 2019 в 01:18
поделиться

Я подозреваю, что несколько компиляторов могли оптимизировать обоих, чтобы быть тем же кодом, но конечно не всеми. Таким образом, я сказал бы, что Вы более обеспечены с первым. Единственная причина для последнего состоит в том, если Вы хотите удостовериться, что заявленная переменная используется [только 111] в Вашем цикле.

5
ответ дан Stew S 23 November 2019 в 01:18
поделиться

Как правило я объявляю свои переменные в самом внутреннем объеме. Так, если бы Вы не используете intermediateResult за пределами цикла, тогда я пошел бы с B.

5
ответ дан Chris 23 November 2019 в 01:18
поделиться

Я всегда использовал бы (вместо того, чтобы полагаться на компилятор) и мог бы также переписать к:

for(int i=0, double intermediateResult=0; i<1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

Это все еще ограничивает intermediateResult объемом цикла, но не повторно объявляет во время каждого повторения.

11
ответ дан Triptych 23 November 2019 в 01:18
поделиться

Я всегда думал, что если вы объявите ваши переменные внутри вашей петли, вы тратите память. Если у вас есть что-то вроде этого:

for(;;) {
  Object o = new Object();
}

, то не нужно создавать не только объект для каждой итерации, но для каждого объекта необходимо быть новой ссылкой. Похоже, что если сборщик мусора медленнее, у вас будет куча свисающих ссылок, которые необходимо очистить.

Тем не менее, если у вас есть это:

Object o;
for(;;) {
  o = new Object();
}

, то вы создаете только единую ссылку и присваивая только новый объект каждому раз. Конечно, это может потребоваться немного дольше, чтобы он выходил из спецификации, но тогда есть только одна висящая ссылка на дело.

4
ответ дан 23 November 2019 в 01:18
поделиться

Ниже приведен то, что я написал и составлен в .NET.

double r0;
for (int i = 0; i < 1000; i++) {
    r0 = i*i;
    Console.WriteLine(r0);
}

for (int j = 0; j < 1000; j++) {
    double r1 = j*j;
    Console.WriteLine(r1);
}

Это то, что я получаю от .NET Reflector , когда CIL отображается обратно в код.

for (int i = 0; i < 0x3e8; i++)
{
    double r0 = i * i;
    Console.WriteLine(r0);
}
for (int j = 0; j < 0x3e8; j++)
{
    double r1 = j * j;
    Console.WriteLine(r1);
}

Итак, оба выглядят точно так же после компиляции. На управляемом языке код преобразуется в код CL / Byte и во время выполнения он преобразуется на язык машины. Таким образом, на языке машины двойной не может быть даже не создан на стеке. Это может быть просто реестр, поскольку код отражает, что это временная переменная для функции функции . Есть целый набор правил оптимизации только для петлей. Таким образом, средний парень не должен беспокоиться об этом, особенно на управляемых языках. Есть случаи, когда вы можете оптимизировать управление кодом, например, если вы должны объединить большое количество строк, используя только строку A; A + = Anaterstring [I] VS Использование StringBuilder . Существует очень большая разница в производительности между обоими. Есть много таких случаев, когда компилятор не может оптимизировать ваш код, потому что он не может выяснить, что предназначено в большем объеме. Но это может в значительной степени оптимизировать базовые вещи для вас.

35
ответ дан 23 November 2019 в 01:18
поделиться

A) безопаснее, чем B) ......... Представьте, что вы инициализируете структуру в цикле, а не 'int' или «float», тогда что?

как

typedef struct loop_example{

JXTZ hi; // where JXTZ could be another type...say closed source lib 
         // you include in Makefile

}loop_example_struct;

//then....

int j = 0; // declare here or face c99 error if in loop - depends on compiler setting

for ( ;j++; )
{
   loop_example loop_object; // guess the result in memory heap?
}

Вы наверняка столкнетесь с проблемами утечки памяти !. Следовательно, я считаю, что «A» более безопасная ставка, в то время как «B» уязвима для накопления памяти, особенно при работе с библиотеками с близким исходным кодом. Вы можете проверить использование инструмента «Valgrind» в Linux, в частности вспомогательного инструмента «Helgrind».

0
ответ дан 23 November 2019 в 01:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: