4

There are several questions like this on SO but none of the answers have worked for me. I have tried them all.

I tried to minimize the code I am pasting, but it's kind of hard with this script

I have a comment form that is submitted via ajax to a php script which saves the comment and then gets all the comments and redisplays them so the new comment can be displayed without refreshing the page.

Only sometimes will the comments successfully submit to the database and redisplay properly. Usually almost every other submit the comment will be saved. Every other time nothing seems to happen.

My real issue is the comments not being saved every time one is submitted.

Here is the javascript and the ajax call:

$(document).ready(function(){
    var working = false;

    $('#commentForm').submit(function(e){

        if(working) return false;

        working = true;
        $('#submitComment').val('Working..');
        $('span.error').remove();

        $.post('/ajax/comment.process.php',$(this).serialize(),function(msg){

            working = false;
            $('#submitComment').val('Submit');

            if(msg.status){

                $('#commentArea').slideDown().$(msg.html).prepend('#commentArea');
            $('#blogComment').val('');
            }
            else {

                $.each(msg.errors,function(k,v){
                    $('label[for='+k+']').append('<span class="error">'+v+'</span>');
                });
            }
        },'json');
    });
});

and here is the function that submits the comment:

public function addComment($user_id) {

    $validate = new data_validation;

    $_POST = $validate->sanitize($_POST);

    $newCom = $_POST['blogComment'];
    $blog_id = intval($_POST['blogID']);
    $photoSubmit = $_POST['comPhoto'];

    $newComQuery = $this->mysqli->query("INSERT INTO b_comments (blog_id, user_id, date, content, photo) VALUES ('".$blog_id."', '".$user_id."', Now(), '".$newCom."', '".$photoSubmit."')");

    if($newComQuery === false) {
        echo "Query failed";
    }else{

        $returnCom = $this->comMarkup($blog_id);
        echo $returnCom;

    }           
}

and here is a piece of the comMarkup() function that echos the comments (it is only the important pieces):

//  This method outputs the XHTML markup of the comment
public function comMarkup($blog_id) {

    $sql = $this->mysqli->query("SELECT * FROM b_comments WHERE blog_id = '".$blog_id."' ORDER BY date DESC");

    while($d = $sql->fetch_assoc()) {

        $d = $validate->sanitize($d);

        echo "

            <div class='comment-block'>
                <span class='com-img'><img src='".$photo_path."' /></span>
                <h3 style='display: inline;'><a href='".$profile."'>".$userName."</a></h3>
                <div class='com-date'>".$d['date']."</div>
                <p>".$comContent."</p>
            </div>
        ";
    }
}

EDIT: Here is the comment.process.php code as requested:

    session_start();

include_once('../classes/comment.class.php');
include_once('../classes/db.class.php');
include_once('../classes/user.class.php');

$user_id = $_SESSION['user_id'];

$db = new DBConnection;
$comments = new Comment($db);
$user = new User($db);

$blogID = intval($_POST['blogID']);

$addCom = $comments->addComment($user_id);

echo json_encode(array('status'=>1,'html'=>$addCom));
Ty Bailey
  • 2,392
  • 11
  • 46
  • 79
  • It seems there is some problem with the variable '**working**'. Are you sure it is implemented correctly? – GBRocks Mar 13 '13 at 03:49
  • I guess I'm not sure it is, however I removed it completely and it still wasn't working. – Ty Bailey Mar 13 '13 at 04:14
  • where you used `$('#blogComment').val()`? – Amir Mar 13 '13 at 14:40
  • @Amir I don't understand what you are asking? – Ty Bailey Mar 13 '13 at 17:11
  • @TyBailey I mean, where do you post `$('#blogComment').val()` to PHP file for INSERT? – Amir Mar 13 '13 at 19:38
  • the form data is being converted using `$(this).serialize()` – Ty Bailey Mar 13 '13 at 21:45
  • @TyBailey Please put your `comment_process.php` codes – Amir Mar 15 '13 at 10:35
  • comment.process.php code has been added – Ty Bailey Mar 15 '13 at 20:28
  • 4
    When you open your browser's Developer Tools, are you seeing the ajax request being made when you click the submit button. If so is the web server returning 200, or some other error code like 500? Try to first figure out where the problem is. You could always eliminate js/ajax by creating some simple test page with a normal html form that submits to /ajax/comment.process.php – Adam Magaluk Mar 21 '13 at 13:51
  • Include your html code and it may help someone help you.. You may also open your php error log to look for error messages, Firebug console for error messages, learn to use a debugger. http://net.tutsplus.com/tutorials/tools-and-tips/chrome-dev-tools-javascript-and-performance/ – Rick Suggs Mar 25 '13 at 17:35
  • $('span.error').remove();... try $('span.error').hide();.. could be that you're removing this from the DOM and when you try to remove it again, $('span.error') is null or undefined and it throws an error and the function breaks..... or do a null/undefined check before you call .remove() – robert Mar 26 '13 at 21:35

9 Answers9

1

Given your description, my guess is that it has something to do with your working variable, and the fact that it is not set to false at the end of your $.post().

But there are a few logic, efficiency, and manageability issues with the way you've drawn up the process. I'd recommend having a look at the official jQuery docs for $.post(), specifically the .done(), .fail(), and .always() chained methods.

I'd also recommend naming your PHP variable something other than $_POST, so it does not become confused with the PHP super global.

Finally, I'd recommend treating your comment as an object and using PDO (this is a link to PDO:query as a kind of "immersion" approach but be sure to read all the docs). It will save you a ton of headaches in database interaction.

dyelawn
  • 750
  • 5
  • 17
  • I am too far into this project to switch to PDO. Thanks for the tips, i'll look into the docs a little more. As of right now, I am still unable to get this working even with removing the `working` variable – Ty Bailey Mar 13 '13 at 04:13
1

It looks like you've got a race condition caused by the working flag. Since you're just using that flag to show the "working..." message and prevent submits while a request is processing, I would just use the normal $.ajax call and put the "working" logic in the beforeSend option. Here's an example:

$(document).ready(function(){
    $('#commentForm').submit(function(e){
        $.ajax({
            type: 'POST'
            url: '/ajax/comment.process.php',
            dataType: 'json',
            beforeSend: function(jqXHR, settings) {
                $('#submitComment').val('Working..');
                $('span.error').remove();
            },
            data: $(this).serialize(),
            complete: function(jqXHR, textStatus) {
                var msg = jqXHR.responseText;
                $('#submitComment').val('Submit');

                if(msg.status){
                    $('#commentArea').slideDown().$(msg.html).prepend('#commentArea');
                    $('#blogComment').val('');
                }
                else {
                    $.each(msg.errors,function(k,v){
                        $('label[for='+k+']').append('<span class="error">'+v+'</span>');
                    });
                }
            };
        });
    });
});
clav
  • 4,221
  • 30
  • 43
0

are you using json_encode()? if not all your echo-backs will be received as "text" and not as an json-object which you're accessing in your jquery

beercan
  • 61
  • 5
  • comMarkup($blog_id) does not return anything as you expect it to: $returnCom = $this->comMarkup($blog_id); echo $returnCom; – beercan Mar 13 '13 at 01:22
  • Where should I use json_encode? Why would this stop it from being displayed? Even if was just coming back as text? – Ty Bailey Mar 13 '13 at 04:20
  • wherever you return the result from php back to jquery. in your code, you expect all data to be return in one variable (msg) in json format (see last argument of the $.post(.."json"). further on you test the property msg.status. this would mean you have to return one array with key 'status' and value true/false from php. next in case of success, you access msg.html. this would require to have all html created by your php function comMarkup to be stored in the same array where the status is under the key "html". – beercan Mar 13 '13 at 10:49
  • 1
    now youre not saving anything in any array, you just echo the html which will result in the output not to be a valid json-encoded string of your data. finally you should store all returning data in one php array $result with $result['status'] = true/false and $result['html'] = 'allyourcreated html'. return all by echo json_encode($result); once at the end of your script – beercan Mar 13 '13 at 10:50
  • Okay, so I am now using this `echo json_encode(array('status'=>1,'html'=>$returnCom()));` to put the status and the html in an array, but I am still having the same issue. – Ty Bailey Mar 13 '13 at 17:22
  • if(msg.status).. before this, put console.log(msg); whats the output? – beercan Mar 13 '13 at 22:25
  • I get no output from `console.log(msg);` when I put it anywhere in my script? Now i'm REALLY confused. – Ty Bailey Mar 13 '13 at 23:43
  • in chrome, open developer tools and then go for the console tab – beercan Mar 14 '13 at 10:21
  • lol I know, it is not logging anything. I put `console.log(msg)` on every line in my JS and it isn't logging anywhere. It's making me think the JS isn't even being executed – Ty Bailey Mar 14 '13 at 15:29
  • thats like unbelievable. supply a link to your problem website – beercan Mar 17 '13 at 01:01
  • beta.hirestarts.com <-- it's a social network that you won't be able to sign in to unless I personally send you an invite. – Ty Bailey Mar 19 '13 at 17:15
  • Did you check the "resources" tab in the Chrome developer console to make sure the JS files are actually being loaded onto the page? (I've run into this problem before for completely unexpected reasons). – Sean Mar 25 '13 at 13:44
0

I guess you should use encodeURIComponent($('#blogComment').val()) somwhere for passing your blogcomment value to PHP file for insert.

Edit 1:

public function addComment($user_id) {

    $validate = new data_validation;

    $_POST = $validate->sanitize($_POST);

    $newCom = rawurlencode($_POST['blogComment']);

if rawurlencode() did not work. use following function:

function encodeURIComponentNew($str) {

    $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
    return strtr(rawurlencode($str), $revert);
}

(function from What is the equivalent of JavaScript's encodeURIcomponent in PHP?)

and then

public function addComment($user_id) {

    $validate = new data_validation;

    $_POST = $validate->sanitize($_POST);

    $newCom = encodeURIComponentNew($_POST['blogComment']);
Community
  • 1
  • 1
Amir
  • 4,089
  • 4
  • 16
  • 28
0

Doubt this is related, but I've had issues in the past when doing ajax stuff using "echo" inside a function, and then trying to echo the returned value again.

Try changing your echo's inside all your functions for "return" instead like so:

public function addComment($user_id) {

    $validate = new data_validation;

    $_POST = $validate->sanitize($_POST);

    $newCom = $_POST['blogComment'];
    $blog_id = intval($_POST['blogID']);
    $photoSubmit = $_POST['comPhoto'];

    $newComQuery = $this->mysqli->query("INSERT INTO b_comments (blog_id, user_id, date, content, photo) VALUES ('".$blog_id."', '".$user_id."', Now(), '".$newCom."', '".$photoSubmit."')");

    if($newComQuery === false) {
        return "Query failed";
    }else{
        $returnCom = $this->comMarkup($blog_id);
        return $returnCom;
    }           
}
BT643
  • 3,495
  • 5
  • 34
  • 55
0

If the user send a comment with ' maybe will happens an error. When you send a comment, the string will broke a mmysqli_query. It can help you, MAYBE.

public function addComment($user_id) {

$validate = new data_validation;

$_POST = $validate->sanitize($_POST);

$newCom = htmlspecialchars($_POST['blogComment'], ENT_QUOTES);
$blog_id = intval($_POST['blogID']);
$photoSubmit = htmlspecialchars($_POST['comPhoto'], ENT_QUOTES);

$newComQuery = $this->mysqli->query("INSERT INTO b_comments (blog_id, user_id, date, content, photo) VALUES ('".$blog_id."', '".$user_id."', Now(), '".$newCom."', '".$photoSubmit."')");

if($newComQuery === false) {
    echo "Query failed";
}else{

    $returnCom = $this->comMarkup($blog_id);
    echo $returnCom;

}           

}

0

It might cause of Browser cookiess. So that In your URL just add addtional queryString for unique URL pattern.

Example:

   $.post('/ajax/comment.process.php?random=randamnumber');
thangavel
  • 82
  • 6
0

So, if I understand the problem correctly, you're submitting the comment and it's not inserting into the database, and it's also presumably not showing you a database error or printing out your Query failed string?

It seems as though your PHP script isn't being executed at all?

If this is the case, I would normally say the most likely culprit for an intermittent error like this is your browser cache. Your browser is looking at the URL, thinks it already knows what content goes with that URL, and returns that content without ever even sending your info to the server. The simplest way to beat that is to add a random querystring to your file call, e.g.:

cachebuster = new Date();
'/ajax/comment.process.php?cachebuster='.cachebuster.getTime();

... I say "normally" since you're using POST and under "normal" circumstances the browser does not cache POST requests. But it is possible, and it's trivial to combat, so give it a shot. This can also be diagnosed, if you use Chrome, by hitting f12, going to the "network" tab, and then running your form. It should tell you if the result was retrieved from cache.

Beyond that, if you're relying on magic_quotes (or worse, you're not relying on magic_quotes), you need to learn the proper way to deal with SQL injection. You should never be inserting untrusted data from the browser directly into the database. Escape it or use parameterized queries. If you're experiencing an intermittent problem with your query, it's probably related to the content of your comment throwing the query off under certain circumstances, as mentioned above, most likely with the inclusion of an apostrophe in a contraction. Diagnose by submitting two forms back to back: trythis and then try'this. If the first one goes and the second one fails, you've likely found your answer. Properly escaping your input would solve this problem.

Ultimately, all of these suggestions have already been given above, but hopefully this provides a little context to help understand the whys and wherefores.


Edit: I see, now that I look closer, that you are in fact escaping your query with a method you haven't shared here. Assuming that's working correctly, then that shouldn't be a concern.

Try echoing out a valid response at the beginning of your script without even executing anything. If that always returns, then you at least know the script is being called successfully.

There could be a problem with your working variable in the event that the ajax call returns with an error. It would never, under those circumstances, set it back to false.

Your #1 ally is the "network" tab in Chrome Developer Tools or watching the response in the console tab in Firefox Firebug extension.


Edit 2:

$.post('/ajax/comment.process.php',$(this).serialize(),function(msg){
    // post stuff, REMOVING the working variable set, cuz it won't be necessary here...
},'json').always(function() { working = false; });
Jason
  • 13,606
  • 2
  • 29
  • 40
  • To clarify, you should *not* set `working` to false at the end of submit, but (according to the $.post docs) rather write it like this: (nm, see 2nd edit in response, it'll format better) – Jason Mar 26 '13 at 18:45
0

You have a SQL Injection vulnerability in your PHP code, make sure you're escaping your variables properly or use a prepared query.

As for the JS part, make sure to return true; at the end of your .submit() function. (for you it would be after the $.post() call)

Also, your 'working' variable can be set forever to true if there's an error in your php script, which is very likely to happen with the SQL Injection Vuln in place.

Explanation: You set it to true, success callback possibly doesn't get called because of error 500 from PHP Backend, so it never gets set to false by your callback, and then you can't ever submit anymore till next page refresh.

Mathieu Amiot
  • 1,204
  • 8
  • 16