Save atomatic in PHP does not work with Success and serialization

Asked

Viewed 387 times

-4

A code that performs the autosave of data on a form works so:

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, by making the following modifications, the autosave if fit to my context, the same 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:

http://www.rrpowered.com/2014/07/auto-save-a-draft-with-php-and-jquery/

  • What error does it make? Can debug javascript/ajax with Firebug or another inspection console?

  • Antonio, shows no error. I used console.debug('Success: ' + data); and absolutely nothing is returned on the console. Auto save stops working. Already with the original code: when updating the form fields or the page, they are automatically restored from the BD in their respective places. @Antonioalexandre

  • So , this and if it will have to break your code and follow up to where it runs, when to stop, pimba, It is there the error, ai se posta...

  • @Magichat, the question is this is not displayed error! I would simply like to know if my logic, or the way I performed the modifications are correct...

  • See when I say error I don’t say you will have a warning about what is wrong, I say that the program stopped at a certain point or the result is not as expected, so I think you need to go testing part by part and see where exactly it stops... For example, give a echo in $title=&$_POST['title']; and see if it is returning the desired value, and so on, the moment the program behaves differently than expected is where the error is likely to be....

  • @Could Magichat give me an email or skype to contact? If you prefer, send me a message there, "lucasbignose" or [email protected].

  • Can you tell if the request is made for the PHP script? In the PHP log some error is displayed?

  • Hello @Marcos, the request is made via Ajax, passing the parameters to the page in PHP and also no error is displayed.

  • @Marcos, could you help me via chat? http://chat.stackexchange.com/rooms/52534/save-atomatico-em-php-nao-funciona-success-e-serializacao

Show 4 more comments

2 answers

1

[COMPLEMENT to Antonio’s response]:

The capture of data serializados on the PHP page, using the structure below [problem presented in the question], it 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 mentioned problem]

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

[PHP of the above mentioned problem]

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

[Solution]

Based on @Filipemoraes' reply: How to take, by reference, string values using PHP, a solution is to catch the return of function serializeArray 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;
};

Thus, applying the solution:

[Javascript]

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

[PHP]:

$title = &$_POST['dados']['title'];
$body  = &$_POST['dados']['body'];
  • Luccas, I think we can do with serialized data tb if we want. In my answer I put it that way because it is the form that I use most. I will try to change here on my machine the code with the way you posted because I think it can be advantageous in case you change to more fields later, do not need to change anything in javascript.

  • Look boy, with the serialization of the object and a check was much better, because I put a condition comparing the JSON of the last form that was sent with the current one and if it is equal, it does not send again, just calls the check again after 10 seconds to see if something has changed. So it only sends the data to update if the content of the form has been changed. I will edit there in the reply. And then I explain here what was changed.

  • Ready, I changed the file autosavedraft.js including the function you passed and put to take instead of the field values, the serialized form and changed the functions.php to take the data tb as you indicated. This had two bonuses: 1) It became unnecessary to change the javascript to include new fields. 2) We can use the serialized form to compare to the last one that was saved in a very simple way, making it only request really if something was modified. Go back in the answer and see the code of the autosavedraft.js and functions.php files

  • It was necessary to change in functions.php the section that affected the Save with tb button, because when the function started to take $_POST["data"] the php code that is executed when saving by clicking with the "Save button" became different. I entered a condition that checks where it came from, if it was for $_POST["data"] sent by ajax or with all the loose variables sent by save button.

  • I understood, excellent @Antonioalexandre, thanks again. If it’s not too much to ask, if you have, could call me there on Skype? lucasbignose or go to chat http://chat.stackexchange.com/rooms/52883/room-for-luccasrodrigo-and-antonio-alexandre

1


Luccas, you followed a tutorial without taking into account that the tutorial could be with errors. And that reference, my friend, was really lame in many parts. So what I did was take the tutorial as a basis and rewrite the code. Now you have a tested example that works.

First, the table and a row 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.');

Then, let’s see the index.php, it started without loading anything and was changed to connect to the database 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>
    <script rel="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 index.php calls, starting with load_form.php, css/autosavedraft.css, js/autosavedraft.js and flash_save.php. Later we will see the code of save.php

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. As this file gave a require in config.php, below follows the code of the same. It will be necessary you adapt the variables with the data of your database.

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");

The following is the CSS code that only had a few changes from the original at the end of the file. Note that the file name 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 say when the form was saved or error. The following are the javascript that makes 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 is executed on the page home loading and is sending the form data every 10 seconds to the autosave.php page.

autosave.php

<?php

require 'functions.php';

echo autosave();

This page was simplified because its code was converted into function and used for when the user clicks on the save button using the same code. Below is the functions.php file that contains the autosave() function that returns 1 if ajax runs successfully and 0 if any 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, updates that line, if it does not exist creates it. All queries have been changed to use Prepared statements and not only a few as in the original tutorial. Now let’s look at the code of 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 giving an echo on the return of the function as does autosave.php, save.php analyzes the return and redirects to the index.php page, passing a saved variable if all went well or a variable error if any error occurred.

Now let’s look at the code of the flash_save.php file 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 pad 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 error variable shows error message which also disappears after 5 seconds.

This is how it works: It loads information that possibly already exists for a given user and is saved every 10 seconds in the database. If a line with the user id does not already exist in the table, it will appear as a blank form. This id can currently be modified in the load_form.php file

This is the example proposed by the tutorial you were doing with some adaptations to see running. The way it was in the tutorial there was no way to see it actually working and so there was no error but also nothing happened.

I hope that answer is satisfactory. Any questions ask in the comments. I thought it was super cool that even though the question was denied by so many people you offered 100 of your reputation to get an answer. You were really interested in knowing what was going wrong. Moral of the story: You did nothing wrong, the tutorial that was kind of lame even.

I suggest redoing everything you’ve done from scratch, re-creating the table, creating the files and changing connection variables, using this code with the filenames I’ve written here in bold on top of each code block.

Big hug and good luck in school.

  • Antonio, thank you so much for your attention. It satisfied nice and still clarified some doubts. Taking advantage of the gap, I know that some members tried to help me, criticized or simply denied, OK, I do not take the credit of those who did not have anything to add, even because I did not know how to make a [mcve] or even several unsuccessful attempts, I could not think of one. However, if everyone had the same disposition, of course, you almost took my hand to program... the forum would bring perhaps much more learning to those who seek it.

  • AH, a minor correction in your code from functions.php, self-execution of the function: (function ajaxPost(){})();, at least for me, it only worked with the addition of this detail.

  • Ué, no functions.php has no javascript. Do you refer to the initial ajaxPost call in autosavedraft.js? This part kept the code that was in the tutorial and here was good: $(Function () { setTimeout(ajaxPost, 10000); }); starting with $ and without the parentheses. Tb I’ve seen in jquery as $(Document). ready(Function() ː ... }); I knew the form you used in this answer: http://answall.com/a/175343/62295. And I’ve used tb as window.load=Function(){...} Anyway I’m glad it worked. Thank you for accepting the reply. :-)

  • That, I apologize, the code is autosavedraft.js. But anyway, if anyone is interested in the solution, if this problem occurs, here are the alternatives.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.