For clarification: the .php files are my professor's and are intended NOT to be changed. The problem arises because $VALORES
in line 186 is uninitialized, and I already issued it to my professor.
This is the code:
<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.log(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;
}
}
?>
As you can see, $VALORES
(publicacion.php) has not been initialized when calling select
in line 186 (that is the warning it gives me whenever I try to do a POST in Postman). The solution is as easy as to remove $VALORES altogether.
To give you an idea, this is the expected result:
{
"RESULTADO": "OK",
"CODIGO": 201,
"DESCRIPCION": "Registro creado correctamente",
"ID": 109,
"TITULO": "",
"FOTOS": []
}
But this is what happens only when the value for "zona" does not exist yet in the database (if it already exists, then the response is always the above):
Warning: Undefined variable $VALORES in C:\xampp\htdocs\pcw\practica2\api\post\publicaciones.php on line 186
{
"RESULTADO": "OK",
"CODIGO": 201,
"DESCRIPCION": "Registro creado correctamente",
"ID": 109,
"TITULO": "",
"FOTOS": []
}
null
As I stated before, I already solved the problem, but my question is about why does it happen and where exactly.
What moment my xhr.response
sets to null
? The only explanation I could find is that rising a warning somehow nullifies the response even if the code is running alright (i.e., without falling into catch and throw statements and without exiting at all).
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType#value:
When setting responseType to a particular value, the author should make sure that the server is actually sending a response compatible with that format. If the server returns data that is not compatible with the responseType that was set, the value of response will be null.
With xhr.responseType = 'json';
you told the browser, that the response would be JSON, and that it should automatically parse it as such for you.
But "random PHP warning message followed by some JSON" is not valid JSON. And so it set the value of your response to null.