1. PHP / Говнокод #2220

    +147.2

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    function post($key)
    {
    	return mysql_escape_string($_POST[$key]);
    }
    
    $sql->Query("SELECT `t1`.*, `t2`.* 
    			FROM `x_local_users` AS `t1`, `x_privs` AS `t2` 
    			WHERE `t1`.`id`=`t2`.`manager_id` 
    			AND `t1`.`login`='".post('userid')."'
    			AND `t1`.`password`='".md5(post('passw'))."' LIMIT 1");

    Где то когда то здесь видел кусок "говнокода", в котором для получения значения глобальных переменных использовались функции.
    Решил на деле испытать такой способ. Очень удобно оказалось использовать, особенно в запросах :)

    Единственное, что не удобно, так это когда в $_SESSION хранится двухмерный массив, и из него вытащить надо чонить =)

    Запостил: nolka4, 04 Декабря 2009

    Комментарии (37) RSS

    • А чем $_POST не устраивает?
      Ответить
    • Ну... Я предпочитаю примерно так:
      function gpc($var, $defval = null)
      {
        if (strlen($var) < 2) return $defval;
        switch ($var{0})
        {
          case 'G': $sg = &$_GET; break;
          case 'P': $sg = &$_POST; break;
          case 'C': $sg = &$_COOKIE; break;
          default: return $defval;
        }
        $key = substr($var, 1);
        $value = (isset($sg[$key])) ? (MAGIC_QUOTES ? stripslashes($sg[$key]) : $sg[$key]) : $defval;
        if (is_int($defval)) $value = intval($value);
        return $value;
      }

      Примеры:
      gpc('Gtest') - возвращает $_GET['test'] или NULL, если такая переменная не передана;
      gpc('Pmessage', '') - $_POST['message'] или пустая строка (аналогично);
      gpc('Ppost_id', 0) - $_POST['post_id'], принудительно приведённый к целому типу, или 0.
      > А чем $_POST не устраивает?
      Тем, что использование таких вот функций-обёрток упрощает работу с $_POST, позволяя не писать длинных строк типа
      $message = isset($_POST['message']) ? $_POST['message'] : '';
      Ответить
      • Ну да не приходится писать длинных строк, только потом втыкай в ваши Gtest и пр. при чтении таких вот проектов. Плюс время выполнения растет при использовании таких вот оберток, и главное почему? А по тому, что лень писать...
        Ответить
        • пишите на асме сразу, раз так беспокоитесь о времени. В моем примере используется стандартный вариант с экранированием переменной, который ни чуть не медленнее обычного кода без таких сокращений. Или вы не экранируете значения переменных в запросе?
          Ответить
          • Я не экранирую :) Экранирует библиотека для работы с BD, с прямыми SQL запросами я уже года полтора как не работаю
            Ответить
            • ну вот, а еще жалуетесь на производительность оберток :)
              Ответить
              • Да я не жалуюсь я их не использую :) Экранирование данных производится уже в вызове метода который строит запрос к БД Во всех остальных случаях работа ведется с переменными напрямую
                Ответить
        • Для начала скажу о примере обёртки, который я привёл (gpc). Во-первых, весь код комментируется и документируется, так что о назначении догадаться можно. Во-вторых, такого рода обёртка - это одна из часто применяемых низкоуровневых функций, так что при чтении проекта кем-то чужим этот кто-то практически сразу столкнётся с необходимостью залезть в код/документацию и посмотреть, зачем эта функция нужна и как ей пользоваться. Далее, количество переменных, принимаемых из формы, не так уж и велико, поэтому время, затрачиваемое на приём данных с помощью обёртки, оказывается в среднем в несколько десятков раз меньше, чем время выполнения всего остального кода, включающего такие вкусности, как запросы к БД или, может быть, генерацию/обработку изображений (и профилирование это наглядно показывает). По поводу библиотеки для работы с БД: конечно же, без placeholder'ов никуда, и они дают ещё один эшелон защиты. Но я не призываю использовать обёртки (а точнее, возможность приведения типов с их помощью) в первую очередь для защиты от инъекций - фильтрация или валидация данных бывают нужны ещё в массе случаев.

          И да, пора уже высказаться насчёт собственно говнокода. Автору следует задуматься о следующих вещах:
          1) функция mysql_escape_string() is deprecated и в скором времени будет выпилена из PHP. Авторы PHP рекомендуют mysql_real_escape_string() в качестве более надёжной замены.
          2) называть функцию приёма данных из формы И их экранирования просто post - это действительно не лучшая идея. Кто-то чужой, кто положится на смысл названия, может долго удивляться, почему у него вылезают лишние слэши, пока не залезет в код и не узрит тело функции.
          3) а вообще, как отметили выше, писать экранирующую обёртку действительно на хрен не упало, потому что есть плейсхолдеры. Так что пункт 1 тут лишний - при нормальном написании об этих эскейп стрингах думать вообще не приходится, это всё забота библиотеки.
          Ответить
          • что такое плейсхолдеры?
            Ответить
            • Объяснять нет времени, вот всё, что смог быстро найти:
              http://www.phpfaq.ru/slashes
              Прочитай раздел "подготовленные выражения".
              Ответить
          • Вы сейчас экранируете не подумав о том, что этого делать на этом уровне логики нельзя. Подготавливаете для sql? Ну так и экранируйте именно при составлении sql/отправки для конструктура и прочего, ваша мега-обёртка будет работать с PostgreSQL?
            Ответить
            • Обращаю внимание, что обёртка, которую я привёл (gpc), используется для извлечения данных из переменных типа $_POST, но не для экранирования при подстановке в запрос. Про разделение уровней логики я прекрасно понимаю, всему должно быть своё место. Хотя мой прокол в том, что я явно не указал в комментарии к gpc назначение этой обёртки - многие не вчитываются в код и судят по ОП-посту.
              Ответить
      • выпей йаду
        залогинился бы только чтоб заминусовать аффтара кода и аффтара комента.
        Ответить
        • Как обоснованно, обстоятельно и аргументированно. Батя грит маладца.
          Ответить
          • - а если нужно получить именно то, что передано (без экранирования и т.д.)? - костыль
            - а если самому нужно положить в массив какую-нибудь переменную ?? - костыль

            не пробовали реализовать в виде статического класса? и нормально реализовать необходимые возможности в нём.

            ps. если эти примеры взяты из книжки, то к ней должен прилогаться пузырёк с йадом
            Ответить
            • - а если нужно получить именно то, что передано (без экранирования и т.д.)? - костыль
              Если ты про говнокод, то 100% прав. А вон то gpc вообще немножеко не о том, это вещь просто для доставания переменных из формы, а не подстановки в запрос.
              - а если самому нужно положить в массив какую-нибудь переменную ?? - костыль
              В какой массив?
              не пробовали реализовать в виде статического класса? и нормально реализовать необходимые возможности в нём.
              Не буду разводить срачь между фанатами и противниками ООП и промолчу.
              Ответить
            • когда я писал этот код, я думал только об экранировании переменных для запросов. Если бы нужно было что то другое - сделал бы что то другое :)
              Ответить
              • экранировать нужно, только если ты куда-то сохраняешь, или выводишь или где нить ещё, где можно чего-нибудь сломать
                Ответить
    • Собственно говно здесь:
      [code language=php]md5(post('passw'))[/code]
      - в этом случае экранировать не надо было
      Ответить
      • ага, ебашим в запрос неэкранированный юзеринпут!
        Ответить
        • а хотя да, есть что то в ваших словах правдивое. туда ж в итоге придет хэш от того что ввели, а не сам пасс :)
          Ответить
          • Именно. А хэш описывается выражением /[0-9a-f]{32}/, там попросту нету опасных символов.
            Ответить
            • но с другой стороны, это может быть своебразной солью :)
              Ответить
              • В смысле? Не понял тебя.
                Ответить
                • http://deforum.ru/forum/viewtopic.php?t=62339 - вот тут описано примерно то, о чем я говорил
                  Ответить
                  • Что ж, полагаю, суть просаливания хэшей из этой статьи ты уяснил. Отмечу, что в ней содержится одно корявенькое утвержедние:
                    > Как правило, SALT - это строка из 4...8 случайных символов, которая <...> сохраняется вместе с финальным хэшем (как, к примеру, сделано в MD5 (Unix)-хэшах)
                    Обрати внимание на подчёркнутое. Unix crypt() действительно автоматически просаливает хэш и прикрепляет соль к солёному хэшу. Но для MD5 это неверно! MD5 даёт однозначное соответствие между строкой и её хэшем, поэтому просаливать MD5-хэши надо самому. Навскидку:
                    define('SALTLEN', 16);
                    
                    function md5salt($pass)
                    {
                      $salt = '';
                      for ($i = 0; $i < SALTLEN; ++$i)
                        $salt .= chr(($x = mt_rand(48, 63)) > 57 ? $x + 39 : $x);
                      return $salt.md5($pass.$salt.$pass.$salt.$pass);
                    }
                    
                    function isHashValid($pass, $hash)
                    {
                      $salt = substr($hash, 0, SALTLEN);
                      return md5($pass.$salt.$pass.$salt.$pass) == substr($hash, SALTLEN);
                    }

                    В функцию md5() в данном случае подаётся исходный пароль, переёбанный с солью (конкретный способ переёбывания не важен - главное сделать и потом уже не трогать ничего). И да, на выходе md5salt() получается строка из hex-символов, что, опять же, безопасно для подстановки в запрос.
                    Ответить
    • mysql_escape_string, кстати, "deprecated"
      Ответить
    • пиздец сборище гениев
      кто там не работает на прямую с БД ? ОРМ используешь? флаг тебе в руки, построй-ка запрос с 3-мя джоинами в котором один будет на подселект с джоином
      и потом попробуй прочитать полученный код без взрыва мозга

      экранировать надо перед вставкой в базу или перед выводом в браузер (если данные не обязательно сувать в базу) . а всякие айдишники надо приводить к типу, блять! $q="UPDATE users SET note = 'loh' WHERE user_id = ".(int)$_GET['id'];
      идея ясна?
      жраьт говно суки! идите нахуй или на форумы и учитесь. за вами потом "проекты" ваши доделывать - ёбнуться можно
      Ответить
      • Давай ты сначала весь тред внимательно прочитаешь, о Великий, а потом поймёшь, что наговорил кучу тупых банальностей, которые тут ВСЕ прекрасно понимают. А лучше просто уйди.
        Ответить
      • ну я в своем проекте если передаю скриптам всякие целочисленные значения, то передаю их как (int)post('user_id')
        Ответить
        • Ты, надеюсь, не забываешь то, о чём уже неоднократно говорилось - что твоя функция post() выполняет экранирование для подстановки в запрос, которое совсем не всегда нужно (ты ведь не только в базу пихаешь принятые данные, но и, возможно, на экран)? И да, она ещё совсем не учитывает влияние magic_quotes_gpc. В случае, если эта опция включена на хостинге (а так очень много где), ты будешь наслаждаться лишними слэшами по полной программе. И, как уже говорилось, на хуй пошли все эти (int) и mysql_escape_вротмненоги (при подстановке в запрос, я имею в виду) - в хотя бы сколь-нибудь крупных проектах надо использовать PDO или любую другую БД-обёртку и не ебать мозги.
          Ответить
          • у меня cвой собственный сервак, и волжебные кавычки выключены :)

            на других проектах я такое еще не использовал. Если и буду использовать дальше - усовершенствую эти функции
            Ответить
        • Вообще, (int) приводит к типу integer, размеры которого платформозависимы.
          Максимальный integer в PHP может быть меньше максимального интежера Базы (например, в Оракле максимально число это 38 девяток, в Мускуле там тоже нехило)

          Так что правильней выходит проверять регуляркой параметры, что там содержатся одни цифры. /^\d+$/
          Ответить
          • Не надо регуляркой, есть расово верная функция ctype_digit(), она работает куда быстрее.
            Ответить

    Добавить комментарий