Save atomic in PHP does not work with success and serialization

-4

A code that does autosave of data in a form works like this:

autosave.php

<?php
require_once '../multiinjet/web/includes/configuracao.php';
try {

    /*Pegar valores postados no formulário*/
    $title=&$_POST['title'];
    $body=&$_POST['body'];

    /*ID do usuário*/
    $user_id=1;  

    $query = $conecta->prepare("SELECT * FROM autosave WHERE user='$user_id'");
    $query->execute();
    $resultado = $query->fetchAll(PDO::FETCH_ASSOC);
    $return_count = $query->rowCount();

if($return_count > 0){     

    if(isset($title) || isset($body)){
    /*Atualizar autosave*/
        $update_qry = $conecta->prepare("UPDATE autosave SET msg_title='$title', msg_body='$body' WHERE user='$user_id'");
        $update_qry -> execute(); 
    } else {
    /*Pegar dados salvos no BD*/ 
        $get_autosave = $conecta->prepare("SELECT * FROM autosave WHERE user='$user_id'");
        $get_autosave->execute();
        while ($gt_v = $get_autosave->fetch(PDO::FETCH_ASSOC)) {
            $title=$gt_v['msg_title'];
            $body=$gt_v['msg_body']; 

            echo json_encode(array('title' => $title, 'body' => $body));
        }           
    }
} else { 
/*Inserir as variáveis no BD*/ 
    $insert_qry = $conecta->prepare("INSERT INTO autosave (user, msg_title, msg_body) VALUES (?, ?, ?)");
    $insert_qry->execute(array($user_id, $title, $body));  
}
} catch(PDOException $e) {
    echo $e->getMessage();
    }
?>

JavaScript:

$(function () {
        $.post("autosave.php", function (data) {
            $("[name='title']").val(data.title);
            $("[name='body']").val(data.body);
        }, "json");
        setInterval(function () {
            $.post("autosave.php", $("#form").serialize());
        }, 2000);
    });

HTML:

<body>
    <div class="center">
        <div class="saved"></div>
        <form id="form">
            <input type="text" name="title" placeholder="Title" autofocus>
            <textarea type="text" name="body" placeholder="Body"></textarea>
            <input type="submit" value="Send">
        </form> 
    </div> 
</body>
  

However, when you make the following changes so that the autosave is   setting to my context, it does not work.

Replace [autosave.php] :

/*Pegar valores postados no formulário*/
    $title=&$_POST['title'];
    $body=&$_POST['body'];

By [autosave.php] :

/*Pegar valores postados no formulário: dados*/
    $dados = json_decode(file_get_contents('php://input'), true);
    $p = $dados['dados']; // pega o serializado do AJAX
    parse_str($p, $dados); // transforma em array de PHP
    $title  =  $dados['title'];
    $body   =  $dados['body'];

Add [autosave.php] :

$resultado = $query->fetchAll(PDO::FETCH_ASSOC);

foreach($resultado as $res){
    $titulo = $res['msg_title'];
    $corpo  = $res['msg_body'];
}

Replace [autosave.php] :

if(isset($title) || isset($body))

By [autosave.php] :

if(($title != $titulo) || ($body != $corpo))

Replace [JavaScript] :

$(function () {
    $.post("autosave.php", function (data) {
        $("[name='title']").val(data.title);
        $("[name='body']").val(data.body);
    }, "json");
    setInterval(function () {
        $.post("autosave.php", $("#form").serialize());
    }, 2000);
});

By [JavaScript] :

setInterval(function () {           
    var dados = $('#form').serialize();
    $.ajax({
      method  : 'POST',
      url     : 'autosave.php',
      dataType: 'json',
      data : {'dados': dados},//
      headers : {'Content-Type': 'application/x-www-form-urlencoded'},
      success: function(data){
         console.debug('Success: ' + data);
         $("[name='title']").val(data.title);
      }
     })
}, 2000);

Reference :

link

    
asked by anonymous 25.01.2017 / 22:37

2 answers

1

Luccas, You followed a tutorial without taking into account that the tutorial could be in error. And that of reference my friend, was really capenga in many parts. So what I did was take the tutorial as a basis and rewrite the code. You now have a tried-and-tested example that works.

First, the table is one line for testing:

CREATE TABLE 'autosave' (
  'id' int(15) NOT NULL AUTO_INCREMENT,
  'user_id' int(15) NOT NULL,
  'msg_title' varchar(255) NOT NULL,
  'msg_body' varchar(255) NOT NULL,
  PRIMARY KEY ('id')
);

INSERT INTO 'autosave' ('id', 'user_id', 'msg_title', 'msg_body') VALUES
(1, 1, 'Teste do autosave', 'Teste de mensagem que ficará sendo autosalva de poucos em poucos segundos.');

Next, we will see the index.php, it started without loading anything and was changed to connect in the bank and bring the test line.

index.php

<?php
    require 'load_form.php';

?>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Auto Save Draft</title>
    <link rel="stylesheet" type="text/css" href="css/autosavedraft.css" />
    <script rel="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script><scriptrel="text/javascript" src="js/autosavedraft.js"></script>
</head>
<body>
    <div id="flash_container">
        <div id="flash_message"></div>
    </div>

    <div class="center">
        <form  action="save.php" method="POST">
            <input type="hidden" name="user_id" value="<?php echo $user_id; ?>">
            <input type="text" name="title" value="<?php echo $title; ?>" placeholder="Title" autofocus>
            <textarea type="text" name="body" placeholder="Body"><?php echo $body; ?></textarea>
            <input type="submit" value="Salvar">
        </form> 

        <p>
            <small>O formulário será salvo automaticamente a cada 10 segundos.</small>
        </p>        
    </div> 

<?php
    require 'flash_save.php'; // chama os alertas de saved ou error com javascript após salvar com o botão Salvar
?>

</body>
</html>

Let's continue with the code that index.php calls, starting with load_form.php, css / autosavedraft.css, js / autosavedraft.js, and flash_save.php. We'll look at the save.php code below

load_form.php

<?php

$user_id = 1; // O ideal é que não seja passado pro form, pegar da sessão após algum login
              // Como nesse exemplo não estou usando session, estou passando pelo form

require("config.php"); // traz variável $pdo_connection 


$stmt = $pdo_connection->prepare("SELECT * FROM autosave WHERE user_id=?");
$stmt->execute(array($user_id));


$row = $stmt->fetch(PDO::FETCH_ASSOC);

$title = $row['msg_title'];
$body  = $row['msg_body']; 

load_form.php loads the title and body variables that will be displayed when loading the index.php page. Since this file gave a require in config.php, it follows the code of the same one. You'll need to tailor the variables to your bank's data.

config.php

<?php

//CONFIG CONEXÃO
$db_name = 'testdb';
$db_host= '127.0.0.1';
$db_user = 'root';
$db_password = '';  

$dsn = 'mysql:dbname='.$db_name.';host='.$db_host;

$pdo_connection = new PDO($dsn, $db_user, $db_password);
$pdo_connection->exec("SET CHARACTER SET utf8");

Following is the CSS code that only had a few changes from the original at the end of the file. Notice that the filename is signaling that you should create a css folder and put it in.

css / autosavedraft.css

body, textarea {
  font-family: "arial";  
}

.center {
    width: 780px;
    margin: 30px auto; 
}

input[type="text"], textarea {
    padding: 20px;
    margin: 5px;
    -moz-border-radius: 3px;
    -webkit-border-radius: 3px;
    border-radius: 3px;
    border: solid #c5c5c5 1px;
    font-size: 20px;
    outline: none;
    width: 40.5em;
}

input[type="text"]:hover, textarea:hover {
    border: solid #666 1px;
}

textarea {
  height: 300px;  
}

input[type="submit"] {
    margin: 5px;
    background: #2ca5f5;
    background-image: -webkit-linear-gradient(top, #2ca5f5, #2f90cc);
    background-image: -moz-linear-gradient(top, #2ca5f5, #2f90cc);
    background-image: -ms-linear-gradient(top, #2ca5f5, #2f90cc);
    background-image: -o-linear-gradient(top, #2ca5f5, #2f90cc);
    background-image: linear-gradient(to bottom, #2ca5f5, #2f90cc);
    -webkit-border-radius: 4;
    -moz-border-radius: 4;
    border-radius: 4px;
    font-family: Arial;
    color: #ffffff;
    font-size: 20px;
    padding: 20px 30px;
    text-decoration: none;
    border: none;
    cursor: pointer;
}

input[type="submit"]:hover {
    background: #3cb0fd;
    background-image: -webkit-linear-gradient(top, #3cb0fd, #3498db);
    background-image: -moz-linear-gradient(top, #3cb0fd, #3498db);
    background-image: -ms-linear-gradient(top, #3cb0fd, #3498db);
    background-image: -o-linear-gradient(top, #3cb0fd, #3498db);
    background-image: linear-gradient(to bottom, #3cb0fd, #3498db);
    text-decoration: none;
}

::-webkit-input-placeholder {/* WebKit browsers */
    color: #c5c5c5;
}

:-moz-placeholder {/* Mozilla Firefox 4 to 18 */
    color: #c5c5c5;
    opacity: 1;
}

::-moz-placeholder {/* Mozilla Firefox 19+ */
    color: #c5c5c5;
    opacity: 1;
}

:-ms-input-placeholder {/* Internet Explorer 10+ */
    color: #c5c5c5;
}

input[type=text]:focus, textarea:focus {
    box-shadow: 0 0 5px rgba(46, 100, 254, 1);
    border: 1px solid rgba(46, 100, 254, 1);
    padding: 20px;
    margin: 5px;
    font-size: 20px;
}

body { margin:0; padding:0;}
#flash_container { height:30px; padding:0; margin:0; text-align:center; }
#flash_message { padding:10px; display:none; border-bottom:1px solid #ccc; background-color: #fafafa; }
.error { color:#d44; }
.ok { color:#0d4;}

These last styles are for a message that appears at the top of the screen and says when the form was saved or gave error. Next we'll see the javascript that does ajax every 10 seconds.

js / autosavedraft.js

$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

ultimo_form_salvo='';

function ajaxPost()
{

    form_obj = $('form').serializeObject();
    dados_atuais = JSON.stringify(form_obj);

    //alert(dados_atuais);

    if(dados_atuais==ultimo_form_salvo)
        setTimeout(ajaxPost, 10000);
    else    
    $.ajax({
      type: 'POST',
      url: 'autosave.php',
      data: 
      {
        dados: form_obj
      },
      success: function(data) 
      {
        ultimo_form_salvo = dados_atuais;

        if(data==1)
        {
            $("#flash_message").html('<span class="ok">Salvo automaticamente.</span>');
        }
        else
        {
            $("#flash_message").html('<span class="error">Erro no autosalvamento.</span>');
        }

        $("#flash_message").fadeToggle( "slow","linear" );

        setTimeout(function(){

          $("#flash_message").fadeToggle( "slow","linear" );

          setTimeout(ajaxPost, 10000); // chama de novo após 10 segundos

        }, 5000); // esconde depois de 5 segundos

      }
    });         
}

(function () {setTimeout(ajaxPost, 10000); })();

This javascript runs in the initial load of the page and sends the form data every 10 seconds to the autosave.php page.

autosave.php

<?php

require 'functions.php';

echo autosave();

This page has become simplified because its code has been converted into function and used for when the user clicks the save button using the same code. Below is the file functions.php that contains the autosave () function that returns 1 if ajax runs successfully and 0 if an error occurs.

functions.php

<?php

function autosave()
{

    try 
    {
        require("config.php");
        //variável $pdo_connection criada em config.php

        /*Get the posted values from the form*/

        if(isset($_POST["dados"])) 
            $dados = &$_POST["dados"]; // se veio do ajax
        else
            $dados = &$_POST;   // se veio clicando no botão de salvar

        $user_id = $dados['user_id'];
        $title   = $dados['title'];
        $body    = $dados['body'];


        /*Get user id*/
        //$user_id=1;  // vindo agora de um input hidden do form, o ideal é que venha de uma variável de sessão após um login

        $stmt = $pdo_connection->prepare("SELECT * FROM autosave WHERE user_id=?");
        $stmt->execute(array($user_id));

        $return_count = $stmt->rowCount();

        if($return_count > 0)
        {     
            /*Update autosave*/
            $update_qry = $pdo_connection->prepare("UPDATE autosave SET msg_title=?, msg_body=? WHERE user_id=?");
            $update_qry -> execute(array($title, $body, $user_id));   
        }
        else
        {
            /*Insert the variables into the database*/ 
            $insert_qry = $pdo_connection->prepare("INSERT INTO autosave (user_id, msg_title, msg_body) VALUES (?, ?, ?)");
            $insert_qry->execute(array($user_id, $title, $body)); 
        }       


        return '1';
    } 
    catch(PDOException $e) 
    {
        //echo $e->getMessage();
        return '0';
    }


}

This autosave () function checks if there is a line with the user id that came by post, if it exists, update that line if it does not exist. All queries have been changed to use prepared statements and not just some ones as in the original tutorial. Let's now look at the code on the save.php page that uses the same function.

save.php

<?php

require 'functions.php';

$retorno = autosave();

if($retorno)
{
    header("Location: index.php?saved");
}
else
{
    header("Location: index.php?error");
}

Instead of echoing the function return as autosave.php does, save.php parses the return and redirects to the index.php page, passing a saved variable if everything went well or a variable error occurred some error.

Now let's look at the flash_save.php file code that is called in the footer of the index.php page

flash_save.php

<?php

if(isset($_GET["saved"])) 
{
?>
     <script> 
        $("#flash_message").html('<span class="ok">Salvo com sucesso.</span>');
        $("#flash_message").fadeToggle( "slow","linear" );

        setTimeout(function()
        {
          $("#flash_message").fadeToggle( "slow","linear" );
        }, 5000); // esconde depois de 5 segundos   
    </script>
<?php 
}  
else
if(isset($_GET["error"])) 
{
?>
     <script> 
        $("#flash_message").html('<span class="error">Erro ao salvar.</span>');
        $("#flash_message").fadeToggle( "slow","linear" );

        setTimeout(function()
        {
          $("#flash_message").fadeToggle( "slow","linear" );
        }, 5000); // esconde depois de 5 segundos   
    </script>
<?php 
}  
?>

This code pastes a java-script block that activates a message at the top of the screen. If you receive the saved variable, it shows the success message that disappears after 5 seconds. If you receive the variable error it shows error message that also disappears after 5 seconds.

This is how it works: It loads information that may already exist for a particular user and saves itself every 10 seconds in the database. If a row with the user id does not already exist in the table, blank form will appear. This id can currently be modified in the file load_form.php

This is the example proposed by the tutorial that you were doing with some adaptations to be able to see running. The way it was in the tutorial could not really work and so it did not give a mistake but nothing happened either.

I hope this answer is satisfactory. Any questions please ask in the comments. I found it super cool that even the question having been denied by so many people you have offered 100 of your reputation to get an answer. You were really interested to know what was going wrong. Moral of the story: You did not do anything wrong, the tutorial that was half capenga really.

I suggest redoing everything you've done from scratch, rebuilding the table, creating the files, and changing connection variables, using this code with the file names I wrote in boldface above each block of code.

Great hug and good luck in studies.

    
31.01.2017 / 20:37
1

[COMPLEMENT to Antonio's response] :

Capturing data serializados on the PHP page, using the structure below [ problem presented in the question ], is not possible because only $_POST['dados'] will be accessible. $_POST['dados'] is a string and will contain something like: title=titulo&body=corpo and not an array as expected.

[JavaScript of the above problem]

var dados = $('#form').serialize();
$.post("autosave.php", {'dados': dados});

[PHP of the above problem]

$title=&$_POST['title'];
$body=&$_POST['body'];

[Solution]

  

Based on the @FilipeMoraes response: How to get, by reference,   string values using PHP , one solution is to get the return   of the serializeArray function and create a new object:

$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

So, applying the solution:

[JavaScript]

var dados = $('#form').serializeObject();
$.post("autosave.php", {'dados': dados});

[PHP]:

$title = &$_POST['dados']['title'];
$body  = &$_POST['dados']['body'];
    
01.02.2017 / 03:26