"просто" SQL и php

kickbeat

Новичок
Доброго времени суток!

Делаю запрос к БД MS SQL через ajax.
Код:
function getActiveDevice(tec_id, device_id) {
      $.ajax({
          url: "php/sqlQuery.php",
          type: "GET",
          dataType: "json",
          data: {
            tec_id:tec_id,
            device_id:device_id
          },
          success:function(result){
              console.log("Success: ", result);
            },
          error:function(jqXHR, textStatus, errorThrown) {
            console.log('textStatus: '+ textStatus);
            console.log('error: ' + errorThrown);
          }
      });
}

в sqlQuery.php делается выборка и формируется массив
PHP:
<?php
 
$id_tec = $_GET['tec_id'];
$id_device = $_GET['device_id'];
 
// подключение к БД
include_once '../php/DBconnect.php';
 
if ($id_tec == 0) {
  echo json_encode(array("c" => "all"));
  exit();
} else {
    // выборка из объединенных таблиц gftec и Device по полю gftec.tabl=device.id
 
// !!вопрос в этом запросе!!
    $db_query = "SELECT gftec.[Id]
                        ,gftec.[ID_TEC]
                        ,gftec.[dattime]
                        ,gftec.[p]
                        ,gftec.[t]
                        ,gftec.[q]
                        ,gftec.[tabl]
                          ,Device.[ID] as 'id_dev'
                          ,Device.[Name]
                          ,Device.[OrderNum]
                          ,Device.[IdDataType]
              FROM (
                SELECT * FROM gftec WHERE [ID_TEC]=".$id_tec.") AS gftec JOIN (
                SELECT * FROM Device WHERE [Id_tec]=".$id_tec.") AS device ON gftec.[tabl]=device.[ID]
                WHERE gftec.[Id] IN (select max(Id) FROM gftec WHERE gftec.[ID_TEC]=".$id_tec." GROUP BY gftec.[tabl])
                ORDER BY device.[OrderNum]";
}
// формирование массива значений
 
    $odbc_result = odbc_exec($db_connect,$db_query);
    $device_cont = odbc_num_rows($odbc_result);
 
    if ($odbc_result) {
        for ($i=0; $i <$device_cont ; $i++) {
          $res_d_name[$i] = odbc_result($odbc_result,"Name");
          $res_p[$i] = odbc_result($odbc_result,"p");
          $res_t[$i] = odbc_result($odbc_result,"t");
          $res_q[$i] = odbc_result($odbc_result,"q");
          $res_dattime[$i] = date("d:m:Y h:i:s", strtoTime(odbc_result($odbc_result,"dattime")));
          odbc_fetch_row($odbc_result);
      }
       echo json_encode(array('c' => $device_cont, 'd_name' => $res_d_name, 'p' => $res_p, 't' => $res_t, 'q' => $res_q, 'dattime' => $res_dattime));
      } else { 
       echo "\n - table isn't readed"; }
?>
в средствах разработчика браузера результат всего этого:
- в логах "error: SyntaxError: Синтаксическая ошибка"
- в network есть запись о запросе, но получено 0 B

Проблема в том, что данный SELECT был отлажен в MS SQL Server Manadement Studio. И там он отлично работает. Но при копировании запроса в php, результатом становится "синтаксическая ошибка" (результат не меняется, если вместо переменных вставляю явные значения). Как я понимаю, для php чего-то в этом запросе не хватает. Синтаксис php проверялся неоднократно - вместо переменных вставлял обычные значения, все двойные/одинарные кавычки, скобки, точки с запятой - все, вроде бы, на месте, но...

p.s. Не знаю поможет ли эта история, но вот работающий запрос (собственно его и переделываю):
PHP:
    $db_query = "SELECT [Id]
                     ,[ID_TEC]
                     ,[dattime]
                     ,[p]
                     ,[t]
                     ,[q]
                     ,[tabl]
                  FROM [GF].[dbo].[gftec]
                  where [ID_tec]=".$id_tec." and [Id] in (select max(id) from [GF].[dbo].[gftec]
                                                                  where [ID_TEC]=".$id_tec."
                                                                  group by [tabl])";
так вот изначально он был без where в 10-й (предпоследней) строке и все в той же менеджмент студии работал отлично, но при вставке в php работать отказывался. Я уже не помню, как додумался до добавления этой 10-й строки, однако смысла ее добавления ни тогда, ни сейчас так и не понял и воспринимал, как бубен. Но вот второй запрос со схожими симптомами вызывает подозрения...

0
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
Ну так в чем проблема?

Вызови свой php/sqlQuery.php?tec_id=123&device_id=456 прямо в браузере и занимайся отладкой спокойно.

http://phpfaq.ru/debug
 

AnrDaemon

Продвинутый новичок
Проблема, очевидно, в
SELECT * FROM gftec WHERE [ID_TEC]=".$id_tec
SELECT * FROM Device WHERE [Id_tec]=".$id_tec
 

kickbeat

Новичок
Ну так в чем проблема?

Вызови свой php/sqlQuery.php?tec_id=123&device_id=456 прямо в браузере и занимайся отладкой спокойно.

http://phpfaq.ru/debug
эм... ну там все то же самое, что и через обычную консоль. Своей html разметки этот .php не имеет, чтобы визуально контролировать. Остается консоль. То, что переменные от запроса пришли - это видно, то, что ответ 0 - тоже, но, если запрос не отработал, то это естественно. Массив не сформирован, возвращать нечего. А сам текст запроса я не вижу, в каком виде он попадает на обработку.

Проблема, очевидно, в
SELECT * FROM gftec WHERE [ID_TEC]=".$id_tec
SELECT * FROM Device WHERE [Id_tec]=".$id_tec
Честно говоря, для меня не очевидно. Что не так с этими кусками селектов?
 

Фанат

oncle terrible
Команда форума
В том что ты не копируешь рабочий запрос, а переписываешь его от руки

И странно что никто до сих пор про SQL injection не написал
 

kickbeat

Новичок
В том что ты не копируешь рабочий запрос, а переписываешь его от руки

И странно что никто до сих пор про SQL injection не написал
в стартовом сообщении я писал
Синтаксис php проверялся неоднократно - вместо переменных вставлял обычные значения...
после чего оно именно приходило в тот самый вид с конкретными цифрами. Но переменные передаются правильно. Текст самого последнего запроса (который работающий) тоже через те же самые переменные - все работает
 

antson

Новичок
Партнер клуба
@kickbeat, я надеюсь этот скрипт крутиться под IIS в интранете вашей организации ?
 

kickbeat

Новичок
т.е. сделать print $db_query; невозможно ни при каких обстоятельствах
эм... не знаю. Это первое мое знакомство и с пхп и вообще с вэб-программированием. Поэтому пробелов у меня еще ой как много. И в основах их полно в том числе. Спасибо, попробую.
"Не так" готовая SQL injection.
@kickbeat, я надеюсь этот скрипт крутиться под IIS в интранете вашей организации ?
Да, это для внутреннего использования строго ограниченного круга лиц. GET специально использовал, чтобы видеть строку адреса вместе со значениями, принимаемыми переменными
 

kickbeat

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

хм. спасибо тебе, добрый человек, который про print напомнил. В общем понатыкал я этого принта везде, где только можно, начиная от входных данных и заканчивая создаваемым массивом
PHP:
        $arr = array('c' => $device_cont, 'd_name' => $res_d_name, 'p' => $res_p, 't' => $res_t, 'q' => $res_q, 'dattime' => $res_dattime);
        print_r($arr);
Array ( [c] => 6 [d_name] => Array ( [0] => Прямая Т.С [1] => Обратная Т.С [2] => Подпитка Т.С [3] => Пром.вода [4] => Пром. ввод газа [5] => Гор.ввод газа ) [p] => Array ( [0] => 8.0184870000000004 [1] => 1.7380519999999999 [2] => 1.8435520000000001 [3] => -0.18861900000000001 [4] => 4.2474769999999999 [5] => 4.451854 ) [t] => Array ( [0] => 81.0 [1] => 52.0 [2] => 85.0 [3] => 16.0 [4] => -1.0 [5] => -3.0 ) [q] => Array ( [0] => 1869.670044 [1] => 1887.8157960000001 [2] => 0.0 [3] => 0.0 [4] => 10809.722656 [5] => 0.0 ) [dattime] => Array ( [0] => 09:01:2017 11:15:00 [1] => 09:01:2017 11:16:00 [2] => 09:01:2017 11:16:00 [3] => 09:01:2017 11:16:00 [4] => 09:01:2017 11:15:00 [5] => 09:01:2017 11:16:00 ) )
дальше уже только возврат массива... так что прошу прощения, с sql все нормально. Похоже, нужно искать ошибку в другом месте

Нашел...
проблема в выводе массива
PHP:
echo json_encode(array('c' => $device_count, 'd_name' => $res_d_name, 'p' => $res_p, 't' => $res_t, 'q' => $res_q, 'dattime' => $res_dattime));
как только я убираю из массива d_name, ошибка сразу пропадает...
Но за этим как раз я и переделывал запрос. Что такого особенного в этом d_name? Обычные названия...
 
Последнее редактирование:

kickbeat

Новичок
json_last_error ?
Текст в utf-8 ?
либо все ок, либо я не так пользуюсь проверками...

еще раз закину свои коды, т.к. были многочисленные эксперименты
JS - Изменения от первоначального: убрал dataType, добавил cache: "false", в приемник добавил проверку на валидность
Код:
      $.ajax({
          url: "php/sqlQuery.php",
          type: "GET",
         // dataType: "json",
          async: "false",
          cache: "false",
          data: {
            tec_id:tec_id,
            device_id:device_id
          },
          success:function(result){
            try {
              var output = JSON.parse(result);
              console.log(output);
            } catch (e) {
              console.log("Output is not valid JSON: " + result);
            }
          },
          error:function(jqXHR, textStatus, errorThrown) {
            console.log('textStatus: '+ textStatus);
            console.log('error: ' + errorThrown);
          }

      });
в php добавил проверку на валидность (нашел в инете). Т.е. ЛИБО возвращает массив, ЛИБО пробегает по ошибкам... ну или так должно быть...
PHP:
<?php

$id_tec = $_GET['tec_id'];
$id_device = $_GET['device_id'];

// подключение к SQL
include_once '../php/DBconnect.php';

if ($id_tec == 0) {            // если выбран весь филиал (id_tec=0).
  echo json_encode(array("c" => "all station"));
  exit();
} else if ($id_device == 99999)  // если выбран пункт "общие" (id_device=99999). Выборка по всем последним значениям.
  {
    // выборка из объединенных таблиц gftec и Device по полю gftec.tabl=device.id
    $db_query = "SELECT gftec.[Id]
                        ,gftec.[ID_TEC]
                        ,gftec.[dattime]
                        ,gftec.[p]
                        ,gftec.[t]
                        ,gftec.[q]
                        ,gftec.[tabl]
                          ,Device.[ID] as 'id_dev'
                          ,Device.[Name]
                          ,Device.[OrderNum]
                          ,Device.[IdDataType]
                FROM (
                  SELECT * FROM gftec WHERE [ID_TEC]=".$id_tec.") AS gftec JOIN (
                  SELECT * FROM Device WHERE [Id_tec]=".$id_tec.") AS device ON gftec.[tabl]=device.[ID]
              WHERE gftec.[Id] IN (select max(Id) FROM gftec WHERE gftec.[ID_TEC]=".$id_tec." GROUP BY gftec.[tabl])
                ORDER BY device.[OrderNum]";
  } else {
    // если выбран конкретный прибор
    $db_query = "SELECT top (1) [Id]
                     ,[ID_TEC]
                     ,[dattime]
                     ,[p]
                     ,[t]
                     ,[q]
                     ,[tabl]
               FROM [GF].[dbo].[gftec]
               WHERE ID_TEC=".$id_tec." and tabl=".$id_device." ORDER BY [Id] desc";
}

// формирование массива значений запроса
    $odbc_result = odbc_exec($db_connect,$db_query);
    $device_count = odbc_num_rows($odbc_result);

    if ($odbc_result)
    {
        for ($i=0; $i <$device_count ; $i++) {
          $res_dn[$i] = odbc_result($odbc_result,"Name");
          $res_p[$i] = odbc_result($odbc_result,"p");
          $res_t[$i] = odbc_result($odbc_result,"t");
          $res_q[$i] = odbc_result($odbc_result,"q");
          $res_dattime[$i] = date("d:m:Y h:i:s", strtoTime(odbc_result($odbc_result,"dattime")));
          odbc_fetch_row($odbc_result);
      }

        // массив
        $arr = array("c" => $device_cont, "dname" => $res_dn, "p" => $res_p, "t" => $res_t, "q" => $res_q, "dattime" => $res_dattime);
   
      //  print_r($arr);

     // проверка на валидность массива
      if (is_object(json_decode($arr))) {
            echo json_decode($arr);
            exit();
          } else {
            // switch and check possible JSON errors
            switch (json_last_error()) {
                case JSON_ERROR_NONE:
                    $error = 'JSON is valid'; // No error has occurred
                    break;
                case JSON_ERROR_DEPTH:
                    $error = 'The maximum stack depth has been exceeded.';
                    break;
                case JSON_ERROR_STATE_MISMATCH:
                    $error = 'Invalid or malformed JSON.';
                    break;
                case JSON_ERROR_CTRL_CHAR:
                    $error = 'Control character error, possibly incorrectly encoded.';
                    break;
                case JSON_ERROR_SYNTAX:
                    $error = 'Syntax error, malformed JSON.';
                    break;
                // PHP >= 5.3.3
                case JSON_ERROR_UTF8:
                    $error = 'Malformed UTF-8 characters, possibly incorrectly encoded.';
                    break;
                // PHP >= 5.5.0
                case JSON_ERROR_RECURSION:
                    $error = 'One or more recursive references in the value to be encoded.';
                    break;
                // PHP >= 5.5.0
                case JSON_ERROR_INF_OR_NAN:
                    $error = 'One or more NAN or INF values in the value to be encoded.';
                    break;
                case JSON_ERROR_UNSUPPORTED_TYPE:
                    $error = 'A value of a type that cannot be encoded was given.';
                    break;
                default:
                    $error = 'Unknown JSON error occured.';
                    break;
            }

            if ($error !== 'JSON is valid') {
                // throw the Exception or exit // or whatever :)
                print "wrong json: ".$error;
            } else {
              // everything is OK
                print "valid json: ".$error;
            }
          }

        //echo json_encode( Array ( 'c' => 6, 'd_name' => Array ( 'Прямая Т.С', 'Обратная Т.С', 'Подпитка Т.С', 'Пром.вода', 'Пром. ввод газа', 'Гор.ввод газа' ), 'p' => Array ( 8.0184870000000004, 1.7380519999999999, 1.8435520000000001, -0.18861900000000001, 4.2474769999999999, 4.451854 ), 't' => Array ( 81.0, 52.0, 85.0, 16.0, -1.0, -3.0 ), 'q' => Array ( 1869.670044, 1887.8157960000001, 0.0, 0.0, 10809.722656, 0.0 ), 'dattime' => Array ( '09:01:2017 11:15:00', '09:01:2017 11:16:00', '09:01:2017 11:16:00', '09:01:2017 11:16:00', '09:01:2017 11:15:00', '09:01:2017 11:16:00' ) ) );
        //var_dump(array('c' => $device_count, 'd_name' => $res_dn, 'p' => $res_p, 't' => $res_t, 'q' => $res_q, 'dattime' => $res_dattime));
        //echo json_encode(array('c' => $device_count, 'd_name' => $res_dn, 'p' => $res_p, 't' => $res_t, 'q' => $res_q, 'dattime' => $res_dattime));

      }
    else
       {          echo "\n - sqlQuery.php - The table isn't readed";      }
?>

итоги:
в самом sqlQuery.php результат выводит
(!!! т.е. пишет, что все ок, но таки провалившись в ошибки...)
в целом в консоли:
- при убранном dataType:
Output is not valid JSON: valid json: JSON is valid
(!!! т.е. php-шная проверка считает, что все ок (опять же см выше про этот "ок", JS - наоборот... вот такой вот поворот...)
- вернул dataType:
Output is not valid JSON: [object Object]
textStatus: parsererror
error: SyntaxError: Недопустимый знак
textStatus: parsererror
error: SyntaxError: Недопустимый знак
где 1 строка - для случая id_tec==0
2 и 3 - для id_device==99999
и 2 последние - 3 случай для выборки в sqlQuery
(1 и 2 ответ просто для сведений - внимания особо не обращаем, т.к. это временные затычки)
 
Последнее редактирование:

ksnk

прохожий
Output is not valid JSON: valid json: JSON is valid
Очевидно, что строка `valid json: JSON is valid` не является валидным json...
Output is not valid JSON: [object Object]
Это тоже невалидный json/ Вероятно, кто-то его уже один раз отjson'ил и уже получил объект
 
Последнее редактирование:

kickbeat

Новичок
Очевидно, что строка `valid json: JSON is valid` не является валидным json...

Это тоже невалидный json/ Вероятно, кто-то его уже один раз отjson'ил и уже получил объект
согласен, первое и не может пройти проверку, НО почему оно вообще в обработку попадает?
PHP:
if (is_object(json_decode($arr))) {
            echo json_decode($arr);
            exit();
          } else {
            // switch and check possible JSON errors
            switch (json_last_error()) {
                case JSON_ERROR_NONE:
                    $error = 'JSON is valid'; // No error has occurred
                    break;
как трактовать такое поведение в этом куске? Т.е. это то ли не объект, то ли не деJSONится, но при этом по last_error'у все отлично - error'ов нет...

и главный же вопрос так и остается - что такого невалидного в возвращаемом массиве (а если совсем точно, то во входящем в него массиве "dname")?
Если подумать, то единственное отличие, которое я вижу, это русские названия... var_dump показал, что все переменные в массиве, кроме первого счетчика (он типа INT) строковые. Т.е. с типами данных, вроде бы, порядок. Соответственно, единственное, что приходит на ум - кодировка. Но проверку то я воткнул. Там есть возврат ошибки кодировки, но оно не отрабатывает. т.е. все ок получается опять?
По кускам - все ок, а как в целом - все плохо..
 

kickbeat

Новичок
Действительно в кодировке причина:

PHP:
$res_d_name[$i] = iconv('windows-1251', 'utf-8', odbc_result($odbc_result,"Name"));
всем спасибо. Проблема решена
 
Сверху