PHP вставляет апострофы там, где это не должно - PullRequest
0 голосов
/ 01 апреля 2010

Не слишком уверен, что здесь происходит, поскольку это не кажется мне стандартной практикой. Но в основном у меня есть базовая база данных, которая позволяет пользователям отправлять фрагменты кода. Они могут предоставить до 5 тегов для представления.

Теперь я все еще учусь, поэтому, пожалуйста, прости меня, если это очевидно!

Вот скрипт PHP, который заставляет все это работать (обратите внимание, что там могут быть некоторые специфические функции CodeIgniter):

function submitform()
  {
    $this->load->helper(array('form', 'url'));

    $this->load->library('form_validation');
    $this->load->database();

    $this->form_validation->set_error_delimiters('<p style="color:#FF0000;">', '</p>');

      $this->form_validation->set_rules('title', 'Title', 'trim|required|min_length[5]|max_length[255]|xss_clean');
      $this->form_validation->set_rules('summary', 'Summary', 'trim|required|min_length[5]|max_length[255]|xss_clean');
      $this->form_validation->set_rules('bbcode', 'Code', 'required|min_length[5]'); // No XSS clean (or <script> tags etc. are gone)
      $this->form_validation->set_rules('tags', 'Tags', 'trim|xss_clean|required|max_length[254]');

    if ($this->form_validation->run() == FALSE)
    {
        // Do some stuff if it fails
    }
    else
    {  
      // User's input values
      $title   = $this->db->escape(set_value('title'));
      $summary = $this->db->escape(set_value('summary'));
      $code    = $this->db->escape(set_value('bbcode'));
      $tags    = $this->db->escape(set_value('tags'));

      // Stop things like <script> tags working
      $codesanitised    = htmlspecialchars($code);

      // Other values to be entered
      $author = $this->tank_auth->get_user_id();

       $bi1 = "";
       $bi2 = "";

       // This long messy bit basically sees which browsers the code is compatible with.
       if (isset($_POST['IE6'])) {$bi1 .= "IE6, "; $bi2 .= "1, ";} else {$bi1 .= "IE6, "; $bi2 .= "NULL, ";}
       if (isset($_POST['IE7'])) {$bi1 .= "IE7, "; $bi2 .= "1, ";} else {$bi1 .= "IE7, "; $bi2 .= "NULL, ";}
       if (isset($_POST['IE8'])) {$bi1 .= "IE8, "; $bi2 .= "1, ";} else {$bi1 .= "IE8, "; $bi2 .= "NULL, ";}
       if (isset($_POST['FF2'])) {$bi1 .= "FF2, "; $bi2 .= "1, ";} else {$bi1 .= "FF2, "; $bi2 .= "NULL, ";}
       if (isset($_POST['FF3'])) {$bi1 .= "FF3, "; $bi2 .= "1, ";} else {$bi1 .= "FF3, "; $bi2 .= "NULL, ";}
       if (isset($_POST['SA3'])) {$bi1 .= "SA3, "; $bi2 .= "1, ";} else {$bi1 .= "SA3, "; $bi2 .= "NULL, ";}
       if (isset($_POST['SA4'])) {$bi1 .= "SA4, "; $bi2 .= "1, ";} else {$bi1 .= "SA4, "; $bi2 .= "NULL, ";}
       if (isset($_POST['CHR'])) {$bi1 .= "CHR, "; $bi2 .= "1, ";} else {$bi1 .= "CHR, "; $bi2 .= "NULL, ";}
       if (isset($_POST['OPE'])) {$bi1 .= "OPE, "; $bi2 .= "1, ";} else {$bi1 .= "OPE, "; $bi2 .= "NULL, ";}
       if (isset($_POST['OTH'])) {$bi1 .= "OTH, "; $bi2 .= "1, ";} else {$bi1 .= "OTH, "; $bi2 .= "NULL, ";}

       // $b1 is $bi1 without the last two characters (, ) which would cause a query error
       $b1 = substr($bi1, 0, -2);
       $b2 = substr($bi2, 0, -2);

// :::::::::::THIS IS WHERE THE IMPORTANT STUFF IS, STACKOVERFLOW READERS::::::::::

       // Split up all the words in $tags into individual variables - each tag is seperated with a space
      $pieces = explode(" ", $tags);
      // Usage:
      // echo $pieces[0]; // piece1 etc

      $ti1 = "";
      $ti2 = "";

      // Now we'll do similar to what we did with the compatible browsers to generate a bit of a query string
      if ($pieces[0]!=NULL) {$ti1 .= "tag1, "; $ti2 .= "$pieces[0], ";} else {$ti1 .= "tag1, "; $ti2 .= "NULL, ";}
      if ($pieces[1]!=NULL) {$ti1 .= "tag2, "; $ti2 .= "$pieces[1], ";} else {$ti1 .= "tag2, "; $ti2 .= "NULL, ";}
      if ($pieces[2]!=NULL) {$ti1 .= "tag3, "; $ti2 .= "$pieces[2], ";} else {$ti1 .= "tag3, "; $ti2 .= "NULL, ";}
      if ($pieces[3]!=NULL) {$ti1 .= "tag4, "; $ti2 .= "$pieces[3], ";} else {$ti1 .= "tag4, "; $ti2 .= "NULL, ";}
      if ($pieces[4]!=NULL) {$ti1 .= "tag5, "; $ti2 .= "$pieces[4], ";} else {$ti1 .= "tag5, "; $ti2 .= "NULL, ";} 

       $t1 = substr($ti1, 0, -2);
       $t2 = substr($ti2, 0, -2); 

       $sql = "INSERT INTO code (id, title, author, summary, code, date, $t1, $b1) VALUES ('', $title, $author, $summary, $codesanitised, NOW(), $t2, $b2)";
       $this->db->query($sql); 

          $this->load->view('subviews/template/headerview');
          $this->load->view('subviews/template/menuview');
          $this->load->view('subviews/template/sidebar');

          $this->load->view('thanksforsubmission');
          $this->load->view('subviews/template/footerview');
    }
  }

Извините за этот скучный кусок кода там. Я понимаю, что у меня, вероятно, есть несколько плохих практик - пожалуйста, укажите на это, если так.

Вот как выглядит выводимый запрос (он приводит к ошибке и вообще не запрашивается):

A Database Error Occurred
Error Number: 1136

Column count doesn't match value count at row 1

INSERT INTO code (id, title, author, summary, code, date, tag1, tag2, tag3, tag4, tag5, IE6, IE7, IE8, FF2, FF3, SA3, SA4, CHR, OPE, OTH) VALUES ('', 'test2', 1, 'test2', 'test2   ', NOW(), 'test2, test2, test2, test2, test2', NULL, NULL, 1, 1, 1, 1, 1, 1, 1, NULL)

Вы увидите бит после NOW (), 'test2, test2, test2, test2, test2' - я никогда не просил его поместить все это в апострофы. Неужели я?

То, что я мог сделать, это поставить каждую из этих строк так:

 if ($pieces[0]!=NULL) {$ti1 .= "tag1, "; $ti2 .= "'$pieces[0]', ";} else {$ti1 .= "tag1, "; $ti2 .= "NULL, ";}

С одинарными кавычками около $ штук [0] и т. Д. - но тогда моя проблема в том, что это не удается, когда пользователь вводит только 4 тега, или 3, или что-то еще.

Извините, если это худший вопрос в истории, я пытался, но мой мозг превратился в кашу.

Спасибо за вашу помощь!

Jack

Ответы [ 4 ]

2 голосов
/ 01 апреля 2010

Трудно быть уверенным, но я считаю, что это соответствующая строка

$tags = $this->db->escape( set_value( 'tags' ) );

Трудно сказать, так как я не знаю, что set_value() делает

Я собираюсь догадаться, что это превращает строку test2 test2 test2 test2 test2 в 'test2 test2 test2 test2 test2' - эти одинарные кавычки остаются в строке даже после того, как вы взорвете и снова сложите все вместе.

Но, я должен сказать, весь этот код действительно грязный. Фактически, у вас есть проблема, о которой вам даже не нужно беспокоиться (динамическое построение INSERT с переменными столбцами). Это показывает мне слабость вашей схемы - теги должны быть в соотношении N: M (многие-ко-многим) с таблицей code, а не с жестким ограничением столбцов. То, как вы это сделали, нарушает 2-ую нормальную форму нормализации базы данных .

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

1 голос
/ 01 апреля 2010

На самом деле вы говорите делать кавычки, выполняя это:

 $tags  = $this->db->escape(set_value('tags'));

Ваш класс БД не знает, что вы предоставляете несколько значений (как это должно быть?). Он обрабатывает значение, полученное из set_value('tags'), как строку и строки необходимо экранировать.

Позже вы взорвете эту строку:

 $pieces = explode(" ", $tags);

, который должен дать вам, например,

$pieces[0] = "'test1";
$pieces[1] = "test2";
$pieces[2] = "test3'";

Затем вы снова объединяете фрагменты, что в итоге дает вам: «'test1, test2, test3'".

Единственное, что мне кажется странным, это заключительная одинарная кавычка, когда вы удаляете последние символы из строки.

Чтобы решить проблему, вы можете сделать следующее: Не бежать set_value('tags') заранее. Вместо этого избегайте одиночных значений:

if ($pieces[0]!=NULL) {$ti1 .= "tag1, "; $ti2 .= $this->db->escape($pieces[0]) . ',';}

Еще одна проблема: у меня нет понимания структуры вашей БД, но похоже, что tags должен войти в собственную таблицу (и затем относиться либо через отношения один ко многим, либо ко многим). В противном случае вы будете ограничены только шестью тегами. Но это зависит от реальной цели.

То же самое для браузеров: что если новый браузер появится на рынке? Вы должны были бы расширить свой стол. Лучше иметь таблицу со всеми браузерами, например,

   id   |  browser
-------------------
   0    |    IE6
   1    |    IE7
   2    |    IE8
   3    |    FF2
etc.

и связать их через промежуточную таблицу с кодами:

 --table code_browser

 code_id | browser_id
 --------------------
    0    |    0
    0    |    1
    0    |    3
    1    |    2
    2    |    1

 etc.
0 голосов
/ 01 апреля 2010

Дается одна переменная, поэтому она обрабатывается как таковая.

Вы можете использовать операторы if для прямого построения запроса $ sql.

   $sql = "INSERT INTO code (id, title, author, summary, code, date";
        if ($pieces[0]!=NULL) {$sql .= ", tag1"; }
        if ($pieces[1]!=NULL) {$sql .= ", tag2"; }
    ...

и т. Д.

0 голосов
/ 01 апреля 2010

Немного смущен вопросом, но, насколько я понимаю, у вас есть пара проблем

a) Для вашего столбца идентификаторов я бы рекомендовал использовать 0, а не '' (на мой взгляд, он немного читабельнее).

б) Вы определяете свои пустые строки $ti1 = "";

Затем вы добавляете к ним

if ($pieces[0]!=NULL) {$ti1 .= "tag1, "; $ti2 .= "$pieces[0], ";} else {$ti1 .= "tag1, "; $ti2 .= "NULL, ";}

$ ti1 теперь равно tag1,

  if ($pieces[1]!=NULL) {$ti1 .= "tag2, "; $ti2 .= "$pieces[1], ";} else {$ti1 .= "tag2, "; $ti2 .= "NULL, ";}

$ ti1 теперь равно tag1, tag2,

Я думаю, вам следует заняться

  if ($pieces[0]!=NULL) {$ti1 .= "'tag1', "; $ti2 .= "$pieces[0], ";} else {$ti1 .= "'tag1', "; $ti2 .= "'NULL, ";}

(обратите внимание на добавление одинарных кавычек внутри двойных кавычек, поэтому вместо $ ti1 теперь равен tag1, tag2, у вас будет $ ti1 теперь равен 'tag1', 'tag2', и т. д.

в) Я не совсем уверен, что эти теги должны представлять, но я бы создал объединяющую таблицу с идентификатором столбца и тегом ONE . Это означает, что каждый идентификатор будет соответствовать до 5 строк в присоединяющейся таблице. Это позволит вам создавать лучшие запросы для подсчета и т. Д. По этим тегам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...