Почему xhr.response имеет значение null, если в моем PHP-коде возникает предупреждение?

Для уточнения: файлы .php принадлежат моему профессору и НЕ предназначены для изменения. Проблема возникает из-за того, что $VALORES в строке 186 не инициализировано, а я уже выдал его своему профессору.

Это код:

  • nueva.html:
<form onsubmit = "crearPublicacion(event);">
    <div>
        <label>Título:</label>
        <input type = "text" name = "titulo">
    </div>
    <div>
        <label>Texto:</label>
        <textarea name = "texto"></textarea>
    </div>
    <div>
        <label>Zona:</label>
        <input type = "text" name = "zona">
    </div>
    <div id = "fotos">
        <div>
            <input type = "file" name = "fotos[]" accept = "image/*">
            <textarea name = "descripciones[]"></textarea>
        </div>
        <div>
            <input type = "file" name = "fotos[]" accept = "image/*">
            <textarea name = "descripciones[]"></textarea>
        </div>
        <div>
            <input type = "file" name = "fotos[]" accept = "image/*">
            <textarea name = "descripciones[]"></textarea>
        </div>
        <div>
            <input type = "submit">
        </div>
    </div>
</form>
  • nueva.js:
function crearPublicacion(evt) {
    evt.preventDefault();   // Cancela el comportamiento por defecto

    let xhr = new XMLHttpRequest(),
        url = 'api/publicaciones',
        fd  = new FormData(evt.currentTarget),
        usu = JSON.parse(sessionStorage['_datos_']),
        auth = `${usu.LOGIN}:${usu.TOKEN}`;
    
    xhr.open('POST', url, true);
    xhr.responseType = 'json';
    xhr.onload = (evt) => {
        let r = xhr.response;

        console.info(r);
    };
    xhr.setRequestHeader('Authorization', auth);
    xhr.send(fd);
}
  • publicaciones.php:
<?php
require_once('../inc/config.php'); // Constantes, etc ...
require_once('../inc/database.php');

$db    = new Database();
$dbCon = $db->getConnection();
$dbCon->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);

header("Access-Control-Allow-Orgin: *");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");

$RECURSO = explode("/", substr($_GET['prm'],1));
$headers = apache_request_headers();
if (isset($headers['Authorization']))
    $AUTORIZACION = $headers['Authorization'];
elseif (isset($headers['authorization']))
    $AUTORIZACION = $headers['authorization'];

if (!isset($AUTORIZACION))
{ // Acceso no autorizado
  $RESPONSE_CODE    = 403;
  $R['RESULTADO']   = 'ERROR';
  $R['CODIGO']      = $RESPONSE_CODE;
  $R['DESCRIPCION'] = 'Falta autorización';
}
else
{
  $R             = [];  // Almacenará el resultado.
  $RESPONSE_CODE = 200; // código de respuesta por defecto: 200 - OK
  $PARAMS = $_POST;
  list($login,$token) = explode(':', $AUTORIZACION);

  if ( !$db->comprobarSesion($login,$token) )
  {
    $RESPONSE_CODE    = 401;
    $R['RESULTADO']   = 'ERROR';
    $R['CODIGO']      = $RESPONSE_CODE;
    $R['DESCRIPCION'] = 'Error de autenticación.';
  }
  else
  {
    $ID = array_shift($RECURSO);
    try{
      $dbCon->beginTransaction();
      if (!is_numeric($ID)) // NUEVO REGISTRO
      { // Si no es numérico $ID es porque se está creando un nuevo registro
        $titulo        = $PARAMS['titulo'];
        $texto         = nl2br($PARAMS['texto'],false);
        $zona          = $PARAMS['zona'];
        $descripciones = $PARAMS['descripciones'];

        $mysql = 'select * from zona where nombre=:ZONA';
        $RESPUESTA = $db->select($mysql, [':ZONA'=>$zona]);
        if ( $RESPUESTA['CORRECTO'] ) // execute query OK
        {
          if (count($RESPUESTA['RESULT']) > 0)
          { // encontrado
            $idZona = $RESPUESTA['RESULT'][0]['id'];
          }
          else
          { // No existe la zona. Hay que crearla.
            $mysql = 'insert into zona(nombre) values(:NOMBRE)';
            if ( $db->executeStatement($mysql, [':NOMBRE'=>$zona]) )
            {
              $mysql = 'select max(id) as idZona from zona';
              $RESPUESTA = $db->select($mysql, $VALORES);
              if ( $RESPUESTA['CORRECTO'] ) // execute query OK
              {
                if (count($RESPUESTA['RESULT']) > 0)
                { // encontrado
                  $idZona = $RESPUESTA['RESULT'][0]['idZona'];
                }
              }
            }
          }
        }

        $mysql  = 'insert into publicacion(titulo,texto,idZona,autor) ';
        $mysql .= 'values(:TITULO,:TEXTO,:ID_ZONA,:AUTOR)';
        $VALORES             = [];
        $VALORES[':TITULO']  = $titulo;
        $VALORES[':TEXTO']   = $texto;
        $VALORES[':ID_ZONA'] = $idZona;
        $VALORES[':AUTOR']   = $login;

        if ( $db->executeStatement($mysql, $VALORES) )
        {
          $mysql = "select MAX(id) as id_pub from publicacion";
          $RESPUESTA = $db->select($mysql);
          if ($RESPUESTA['CORRECTO'])
          {
            $ID = $RESPUESTA['RESULT'][0]['id_pub'];

            $RESPONSE_CODE    = 201;
            $R['RESULTADO']   = 'OK';
            $R['CODIGO']      = $RESPONSE_CODE;
            $R['DESCRIPCION'] = 'Registro creado correctamente';
            $R['ID']          = $ID;
            $R['TITULO']      = $titulo;
            $R['FOTOS']       = $fotos;
          }
          else
            $ID = -1;
        }
        else
        {
          $RESPONSE_CODE    = 500; // INTERNAL SERVER ERROR
          $R['RESULTADO']   = 'ERROR';
          $R['CODIGO']      = $RESPONSE_CODE;
          $R['DESCRIPCION'] = 'Error indefinido al crear el nuevo registro';
        }
      }
      $dbCon->commit();
    }catch(Exception $e){
      echo $e;
      $dbCon->rollBack();
    }
  }
}
$dbCon = null;
http_response_code($RESPONSE_CODE);
echo json_encode($R);
?>
  • база данных.php:
<?php
class Database{
    private $HOST              = "127.0.0.1";
    private $DB_DATABASE_NAME  = "websocial";
    private $DB_USERNAME       = "pcw";
    private $DB_PASSWORD       = "pcw";
    public  $conn;

    public function __construct() {...}

    public function select($query = "" , $params = [])
    {
        $result = false;
        $RESPUESTA = [];

        try {
            $stmt = $this->conn->prepare( $query );
            if ($stmt === false) {
                throw New Exception("Unable to do prepared statement: " . $query);
            }

            $stmt->execute($params);

            $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
            $stmt->closeCursor();
            $RESPUESTA['CORRECTO'] = true;
        } catch(Exception $e) {
            // throw New Exception( $e->getMessage() );
            $RESPUESTA['CORRECTO'] = false;
            $RESPUESTA['ERROR'] = $e->getMessage();
        }

        $RESPUESTA['RESULT'] = $result;

        return $RESPUESTA;
    }

    public function executeStatement($query = "", $params = [])
    {
        $retVal = false;
        try {
            $stmt = $this->conn->prepare( $query );
 
            if ($stmt === false) {
                throw New Exception("Unable to do prepared statement: " . $query);
            }
 
            if ( $params )
                $retVal = $stmt->execute($params);
            else
                $retVal = $stmt->execute();

        } catch(Exception $e) {
            throw New Exception( $e->getMessage() );
        }   

        return $retVal;
    }

}
?>

Как видите, $VALORES (publicacion.php) не был инициализирован при вызове select в строке 186 (это предупреждение, которое он выдает всякий раз, когда я пытаюсь выполнить POST в Postman). Решение так же просто, как полное удаление $VALORES.

Чтобы дать вам представление, это ожидаемый результат:

{
    "RESULTADO": "OK",
    "CODIGO": 201,
    "DESCRIPCION": "Registro creado correctamente",
    "ID": 109,
    "TITULO": "",
    "FOTOS": []
}

Но это происходит только тогда, когда значение для «зоны» еще не существует в базе данных (если оно уже существует, то ответ всегда будет таким, как указано выше):

  • Почтальон:

Предупреждение: неопределенная переменная $VALORES в C:\xampp\htdocs\pcw\practica2\api\post/publicaciones.php в строке 186.

{
    "RESULTADO": "OK",
    "CODIGO": 201,
    "DESCRIPCION": "Registro creado correctamente",
    "ID": 109,
    "TITULO": "",
    "FOTOS": []
}
  • Консоль JS в отладчике VSCode/Web DevTools:
null

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

В какой момент мой xhr.response переходит на null? Единственное объяснение, которое я смог найти, состоит в том, что появление предупреждения каким-то образом аннулирует ответ, даже если код работает нормально (т. е. без попадания в операторы catch и throw и вообще без выхода).

Не связано, но вам ДЕЙСТВИТЕЛЬНО нужно перестать проверять ошибки вручную. Удалите if ($stmt === false) {, так как это не только не нужно, но и приводит к утечке конфиденциальной информации вашим конечным пользователям.

Dharman 13.04.2023 12:21

Вы спрашиваете, почему $VALORES не определено или почему вы получаете NULL в JavaScript. Ваши вопросы не связаны с MySQL, поэтому их не следует помечать как таковые. Если вы спрашиваете о неопределенной переменной, ответ заключается в том, чтобы просто удалить ее из этой строки.

Dharman 13.04.2023 12:23
$_GET['prm'] Но вы делаете POST из браузера и у вас нет названий полей, которые
RiggsFolly 13.04.2023 12:27

Никакой настоящей «загадки» здесь нет. developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/…: «При установке для responseType определенного значения автор должен убедиться, что сервер действительно отправляет ответ, совместимый с этим форматом. Если сервер возвращает данные, несовместимые с установленным типом ответа, значение ответа будет нулевым». Вы сказали браузеру, что ответ будет в формате JSON, но ваш сервер ответил «случайной тарабарщиной, за которой следует какой-то JSON», и это, конечно, недопустимый JSON.

CBroe 13.04.2023 12:41

@Dharman Файлы .php принадлежат моему профессору, и они не предназначены для изменения (хотя, если есть что-то, что вызывает сбой в работе системы, то я, конечно, должен запросить изменение, как в этом случае), поэтому я должен не изменю того, что вы сказали, но я ценю это, так как в будущем меня попросят кодировать на PHP, так что спасибо.

αγρ 13.04.2023 13:23

Скажите своему профессору, что они учат плохим практикам, и они должны взглянуть на руководство по PHP и обновить его. Школа оказывает вам медвежью услугу, обучая вас писать плохой PHP-код.

Dharman 13.04.2023 13:30

@Dharman Я знаю, почему $VALORES не определено, я спрашиваю, почему я получаю null в консоли JS, когда использую неопределенную переменную, в то время как все остальное работает нормально. При этом я пометил это с помощью MySQL, чтобы быть уверенным, но я с радостью отключу его как таковой, если он не связан. Спасибо.

αγρ 13.04.2023 13:33

@Dharman Да, должны. Я не эксперт по PHP (на самом деле новичок), но вижу, что в API не хватает многих вещей. Не волнуйтесь: я ничего не узнаю из файлов .php, я надеюсь, что они научат меня правильно всякий раз, когда мне ДЕЙСТВИТЕЛЬНО придется программировать на PHP.

αγρ 13.04.2023 13:37

@CBroe О, понятно. Таким образом, HTML из предупреждения, которое отправляет сервер, является причиной того, что оно null в консоли JS. Я вижу, спасибо! Теперь: что мне делать? Я прошу вас сделать это ответом, чтобы я мог пометить его как отвеченный, или я должен сделать ответ, объясняющий это?

αγρ 13.04.2023 13:44
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
9
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType#value:

При установке для responseType определенного значения автор должен убедиться, что сервер действительно отправляет ответ, совместимый с этим форматом. Если сервер возвращает данные, несовместимые с установленным типом ответа, значение ответа будет нулевым.

С помощью xhr.responseType = 'json'; вы сообщаете браузеру, что ответ будет в формате JSON, и что он должен автоматически проанализировать его для вас.

Но «случайное предупреждающее сообщение PHP, за которым следует некоторый JSON», не является допустимым JSON. И поэтому он устанавливает значение вашего ответа равным нулю.

Другие вопросы по теме