Для уточнения: файлы .php принадлежат моему профессору и НЕ предназначены для изменения. Проблема возникает из-за того, что $VALORES
в строке 186 не инициализировано, а я уже выдал его своему профессору.
Это код:
<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>
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);
}
<?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
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": []
}
null
Как я уже говорил, я уже решил проблему, но мой вопрос о том, почему это происходит и где именно.
В какой момент мой xhr.response
переходит на null
? Единственное объяснение, которое я смог найти, состоит в том, что появление предупреждения каким-то образом аннулирует ответ, даже если код работает нормально (т. е. без попадания в операторы catch и throw и вообще без выхода).
Вы спрашиваете, почему $VALORES
не определено или почему вы получаете NULL в JavaScript. Ваши вопросы не связаны с MySQL, поэтому их не следует помечать как таковые. Если вы спрашиваете о неопределенной переменной, ответ заключается в том, чтобы просто удалить ее из этой строки.
$_GET['prm']
Но вы делаете POST из браузера и у вас нет названий полей, которые
Никакой настоящей «загадки» здесь нет. developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/…: «При установке для responseType определенного значения автор должен убедиться, что сервер действительно отправляет ответ, совместимый с этим форматом. Если сервер возвращает данные, несовместимые с установленным типом ответа, значение ответа будет нулевым». Вы сказали браузеру, что ответ будет в формате JSON, но ваш сервер ответил «случайной тарабарщиной, за которой следует какой-то JSON», и это, конечно, недопустимый JSON.
@Dharman Файлы .php принадлежат моему профессору, и они не предназначены для изменения (хотя, если есть что-то, что вызывает сбой в работе системы, то я, конечно, должен запросить изменение, как в этом случае), поэтому я должен не изменю того, что вы сказали, но я ценю это, так как в будущем меня попросят кодировать на PHP, так что спасибо.
Скажите своему профессору, что они учат плохим практикам, и они должны взглянуть на руководство по PHP и обновить его. Школа оказывает вам медвежью услугу, обучая вас писать плохой PHP-код.
@Dharman Я знаю, почему $VALORES
не определено, я спрашиваю, почему я получаю null
в консоли JS, когда использую неопределенную переменную, в то время как все остальное работает нормально. При этом я пометил это с помощью MySQL, чтобы быть уверенным, но я с радостью отключу его как таковой, если он не связан. Спасибо.
@Dharman Да, должны. Я не эксперт по PHP (на самом деле новичок), но вижу, что в API не хватает многих вещей. Не волнуйтесь: я ничего не узнаю из файлов .php, я надеюсь, что они научат меня правильно всякий раз, когда мне ДЕЙСТВИТЕЛЬНО придется программировать на PHP.
@CBroe О, понятно. Таким образом, HTML из предупреждения, которое отправляет сервер, является причиной того, что оно null
в консоли JS. Я вижу, спасибо! Теперь: что мне делать? Я прошу вас сделать это ответом, чтобы я мог пометить его как отвеченный, или я должен сделать ответ, объясняющий это?
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType#value:
При установке для responseType определенного значения автор должен убедиться, что сервер действительно отправляет ответ, совместимый с этим форматом. Если сервер возвращает данные, несовместимые с установленным типом ответа, значение ответа будет нулевым.
С помощью xhr.responseType = 'json';
вы сообщаете браузеру, что ответ будет в формате JSON, и что он должен автоматически проанализировать его для вас.
Но «случайное предупреждающее сообщение PHP, за которым следует некоторый JSON», не является допустимым JSON. И поэтому он устанавливает значение вашего ответа равным нулю.
Не связано, но вам ДЕЙСТВИТЕЛЬНО нужно перестать проверять ошибки вручную. Удалите
if ($stmt === false) {
, так как это не только не нужно, но и приводит к утечке конфиденциальной информации вашим конечным пользователям.