Jump to content

Integrating AJAX with my PHP


TechnoDiver

Recommended Posts

So this is kind of a carry on from my last post about while looping, but I felt it was better to start it in a new thread because the framing of the question has changed. For those of you who responded to my last post I thank you and here is the issue and backstory on that post:

I'm trying to integrate an AJAX infinite scrolling system into a project. I'm really uncomfortable with AJAX and have watched a few tutorials on it and have tried to integrate what I've learned into my PHP. The one tutorial that made the most sense to me also, obviously uses some PHP but it's kept at a basic level and the PHP of my own that I'm integrating it with is quite a bit more in depth.

Before I start with the breakdown, I'd like to make clear that I'm not ignoring anyone's advice on using a foreach over the while loop. The ajax guy is using a while loop in his more simple examples and since I'm so uncomfortable with AJAX I wanted to stay as true to his examples as possible until I got it functioning correctly then I plan on tidying it up. I just want to get it functioning first to where I have a deeper understanding as I'm doing a lot of customization so it fits with my already written code. That being said, I'm going to try to make this post as organized and clear as possible as I really need some help.

I have a news_feed.php includes file that looks like this->



<div class="col-sm-12 col-lg-8 ms-3 me-3 column2">

    <form action="" method="POST">

        <textarea class="form-control" name="post_text" id="text-area" placeholder="Post to your profile" rows="6" autofocus></textarea>
        <div class="buttons">
            <input class="form-group btn btn-outline my-2 button" type="submit" name="submit_post" id="post-button" data-bs-toggle="tooltip" title="Post to your profile" data-bs-html="true" value="Post">
        </div>
    </form>

    <?php //$post->getUserPosts(); ?>

    <div class="posts_area"></div>

    <img src="img/icons/loading.gif" id="loading">

</div> <!-- end newsfeed -->



</div> <!-- end inner row -->
</div>
</div>

It's all pretty straight forward. When the $post->getUserPosts() is uncommented all the posts are displayed. It's commented out right now because of the next 2 files. Next I have an ajax_load_posts.php file that looks like this ->

<?php
require_once($_SERVER["DOCUMENT_ROOT"] . "/qcic/assets/core/init.php");
$user = new User();
$posts = new Post();

$limit = 10; // loaded posts per call

// pull userLoggedIn from ajax script
$request = $_REQUEST['userLoggedIn'];
$posts->getUserPosts($request, $limit);

The last line in this file is why I have the $post->getUserPosts() in the previous one commented out. Next I have the following AJAX. None of this is my code and it's the code I'm trying to integrate into my own project ->

<script>
var userLoggedIn = '<?php echo $user->data()->username; ?>';

$(document).ready(function() {

    $('#loading').show();

    //ajax for loading first posts
    $.ajax({
        url: "includes/handlers/ajax_load_posts.php",
        type: "POST",
        data: "page=1&userLoggedIn=" + userLoggedIn,
        cache: false, 

        success: function(data) {
            $('#loading').hide();
            $('.posts_area').html(data);
        }
    });

    $(window).scroll(function() {
        var height = $('.posts_area').height(); //div containing posts
        var scroll_top = $(this).scrollTop();
        var page = $('.posts_area').find('.nextPage').val();
        var noMorePosts = $('.posts_area').find('.noMorePosts').val();

        if ((document.body.scrollHeight == document.body.scrollTop + window.innerHeight) && noMorePosts == 'false') {
            $('#loading').show();

            var ajaxReq = $.ajax({
                url: "includes/handlers/ajax_load_posts.php",
                type: "POST",
                data: "page=" + page + "&userLoggedIn=" + userLoggedIn,
                cache: false, 

                success: function(response) {

                    $('.posts_area').find('.nextPage').remove(); //removes current next page
                    $('.posts_area').find('.noMorePosts').remove(); //removes current next page
                    $('#loading').hide();
                    $('.posts_area').append(response);
                }

            });

        } // end if

        return false;
    });

});

</script>

Finally I have my getUserPosts() method in my Post class. The majority of this is my code but I've had to make some amendments for this particular task I'm working on. (again, please don't think I'm ignoring anyones advice, I'm not, I will change many things once my understanding is more complete and I get it functioning). ->

<?php

public function getUserPosts($data, $limit) {
// public function getUserPosts() {

    //$page comes from the $_GET data in ajax script
    $page = $data['page'];
    $userLoggedIn = $this->user->username;


    if($page == 1) {
        $start = 0;
    } else {
        $start = ($page - 1) * $limit;
    }

    $table = "un_posts";
    $field = "deleted";
    $value = "no";
    $rule = "ORDER BY id DESC";
    $query = $this->_db->get($table, array($field, "=", $value), $rule);
    $this->_data = $query->all(); // $this->_data is an array of objects

    $str = ""; //html string to return
    if (count($this->_data) > 0) {

        $num_iterations = 0; # number of results checked (not necessarily posted)
        $count = 1;

        // foreach ($this->data() as $obj) {
        //     $post_data = array(
        //         "id" => $obj->id,
        //         "content" => $obj->content,
        //         "added_by" => $obj->add_by,
        //         "date_added" => date("F d, Y H:i:s", strtotime($obj->date_added)),
        //         "user_to" => $obj->user_to,
        //     );

        $cnt = 0;
        while($cnt < count($this->data())) {
            $post_data = array(
                "id" => $this->data()[$cnt]->id,
                "content" => $this->data()[$cnt]->content,
                "added_by" => $this->data()[$cnt]->add_by,
                "date_added" => date("F d, Y H:i:s", strtotime($this->data()[$cnt]->date_added)),
                "user_to" => $this->data()[$cnt]->user_to,
            );

            //prepare user string if it's not posted to a user
            if ($post_data["user_to"] == "none") {
                $user_to = "";
            } else {
                $user_to_obj = new User($post_data["user_to"]);
                $user_to_firstname = $user_to_obj->data()->firstname;
                $user_to_lastname = $user_to_obj->data()->lastname;
                $user_to = "to <a href='" . $post_data["user_to"] ."'>" . $user_to_firstname . " " . $user_to_lastname . "</a>";
            }

            //check if poster has account closed
            $added_by_obj = new User($post_data["added_by"]);

            if ($added_by_obj->isClosed()) {
                continue;
            }

            if($num_iterations++ < $start) {
                continue;
            }

            //load 10 posts and break
            if($count > $limit) {
                break;
            } else {
                $count++;
            }


            //TODO change this for people who use username instead of real names
            $firstname = $added_by_obj->data()->firstname;
            $lastname = $added_by_obj->data()->lastname;

            if ($firstname && $lastname) {
                $name = $firstname . " " . $lastname;
            } else {
                $name = $added_by_obj->data()->username;
            }

            $profile_pic = $added_by_obj->data()->profile_pic;

            //timeframe
            $datetime_now = date("Y-m-d H:i:s");
            $start_date = new DateTime($post_data["date_added"]); //time of post
            $end_date = new DateTime($datetime_now); // current time
            $interval = $start_date->diff($end_date); //difference

            if ($interval->y >= 1) {
                if ($interval == 1) {
                    $time_message = "1 year ago";
                } else {
                    $time_message = $interval->y . " years ago";
                }
            } elseif ($interval->m >= 1) {
                if ($interval->d == 0) {
                    $days = " ago";
                } elseif ($interval->d == 1) {
                    $days = "1 day ago";
                } else {
                    $days = $interval->d . " days ago";
                }

                if ($interval->m == 1) {
                    $time_message = "1 month " . $days;
                } else {
                    $time_message = $interval->m . " months " . $days;
                }
            } elseif ($interval->d >= 1) {
                if ($interval->d == 1) {
                    $time_message = "Yesterday";
                } else {
                    $time_message = $interval->d . " days ago";
                }
            } elseif ($interval->h >= 1) {
                if ($interval->h == 1) {
                    $time_message = "An hour ago";
                } else {
                    $time_message = $interval->h . " hours ago";
                }
            } elseif ($interval->i >= 1) {
                if ($interval->i == 1) {
                    $time_message = "A minute ago";
                } else {
                    $time_message = $interval->i . " minutes ago";
                }
            } elseif ($interval->s < 30) {
                if ($interval->s == 1) {
                    $time_message = "Just now";
                } else {
                    $time_message = $interval->s . " seconds ago";
                }
            }

            $str .= "

                <div class='status_post'>
                    <div class='post_profile_pic'>
                        <img src='../usernet/img/profile_pics/{$profile_pic}' width='50'>
                    </div>

                    <div class='posted_by'>
                        <a href='{$post_data['added_by']}'> {$name} </a> {$user_to} &nbsp;&nbsp;&nbsp;&nbsp; {$time_message}
                    </div>

                    <div id='post_body'>
                        {$post_data['content']}
                        <br>
                    </div>
                </div>
                <hr>";

            $cnt++;
        }

        if($count > $limit) {
            //keeping these hidden just to store the values 
            $str .= "<input type='hidden' class='nextPage' value='" . ($page + 1) . "'>
                    <input type='hidden' class='noMorePosts' value='false'>";
        } else {
            $str .= "<input type='hidden' class='noMorePosts' value='true'><p style='text-align: centre;'> No more posts to show!</p>";
        }
    }

    echo $str;
}

The original commented out at the top (with no parameters) is my original and corresponds to the commented out call to this method in the first file I posted.

As is, this is not showing the posts only the loading.gif from the first file. I suspect it's not reading the ajax_load_post.php file correctly if at all, as that is where the new call to this method is located.

I'm not sure what my actual question is other than "How do I get this working properly?". outside using AJAX for some API calls this is my first foray into using it in a more complex manner. I've tried to keep my code well commented and this post organized so as not to discourage people from responding. I'm pretty lost in the jungle right now and any compass or map any of you could provide would be appreciated. Thank you.

Link to comment
Share on other sites

You call your method like so:

4 hours ago, TechnoDiver said:
// pull userLoggedIn from ajax script
$request = $_REQUEST['userLoggedIn'];
$posts->getUserPosts($request, $limit);

Suggesting that the first parameter is going to be the user id passed in from the URL.  Then you have your method which looks like:

4 hours ago, TechnoDiver said:
public function getUserPosts($data, $limit) {
// public function getUserPosts() {

    //$page comes from the $_GET data in ajax script
    $page = $data['page'];
    $userLoggedIn = $this->user->username;

Here, the first parameter is an array that you're trying to extract the page key from.  You also seem to ignore the userLoggedIn parameter here and just get the user id from within the class somewhere.

You could just pass in $_REQUEST for the first parameter, but it might be nicer to change the first parameter to be $page and pass in $_REQUEST['page'].

public function getUserPosts($page, $limit){
    $userLoggedIn = $this->user->username;
    //...everything else
}

//Then call it
$posts->getUserPosts($_REQUEST['page'], 10);

If you're still having isssues, then you need to debug the ajax requests to see what's happening.  You do that with your browser's developer tools (F12).  Look at the networking tab which will show all the requests made by the browser and find the ajax request in the list.  Check to see if the request returns a successful response (200) and check the details of the request by selecting it.  In the details you can find the parameters that were sent and the response that was returned.  Look at the response that was returned and make sure it is what you're expecting it to be.

 

Link to comment
Share on other sites

5 minutes ago, gizmola said:

So to be clear, you have no security concerns in your app?

It is ok with you that anyone can pass the userLoggedIn parameter to your ajax api call endpoint and see the posts for that user? 

 

No, that's not alright with me actually, I'm just experienced enough to have foreseen it, I'm still trying to get my head around this AJAX. Was doing that as the notification for this comment popped-up actually.

I'm certainly glad you pointed it out though. What would you suggest??

Link to comment
Share on other sites

When you do authentication, keep the status of the authentication in the Session.  There is nothing more or less needed.

The way the session connects to the user is through the session id, which should be configured to only be passed via HTTPS and stored as a cookie.

You write a generic function or method that reads the user information from the session.

  • No user state -> redirect to login
  • If you have some sort of login duration you want to enforce and it's expired, you can also look at that and redirect
  • If the user wants to "escalate" which involves anything having to do with gaining additional access or changing key things in their user/profile, like email, password etc. you reprompt for their password

You can put this logic into a class, or add to the user class, and once you've perfected it, every routine that requires authentication should pass through this routine first, to determine if the user is logged in. This includes ajax routines.  In those routines you can pass back an error state indicating the user is not logged in, or whatever you want your ajax error information to contain.

Link to comment
Share on other sites

22 hours ago, kicken said:

You call your method like so:

Thanks for taking the time on that response, kicken,  it gave me a lot to think about and I managed to get the posts displayed, so at least part of the ajax script is working, but it only displays the top 10 ($limit) and the infinite scroll part of it still isn't working. I've been reading articles, watching videos and staring at it on and off for hours trying to familiarize myself with what the jquery/ajax is actually doing, still have figured it out. Everything in the dev tools seems as it should be. I get the 200 response for the ajax_load file and it helped me fix my mistake that stopped any posts from loading to where I am now - first ten posts load, none of the others do when scrolling. The URL doesn't even change, which I assume it would after hit the scroll point that loads the posts, from the looks of the code.  If you have any other suggestions I'm open to hearing anything on the matter. I feel like a baby in the woods trying to get this jquery working

36 minutes ago, gizmola said:

When you do authentication, keep the status of the authentication in the Session.  There is nothing more or less needed.

Yea, you've given me a whole new dimension to consider. Total noob mistake not seeing that that would be a problem. I'm going to keep it like is for now, only because the project isn't live and I'm also feeling completely overwhelmed by this particular task in the project and I feel that when I get the infinite scroll working properly I can use it as an anchor point while I mess with all the things wrong that I'll need to correct

Link to comment
Share on other sites

On 11/12/2021 at 11:09 AM, TechnoDiver said:
public function getUserPosts($data, $limit) {
    //...
    if (count($this->_data) > 0) {
        $count = 1;
        $cnt = 0;
        while($cnt < count($this->data())) {
            //...
            if($count > $limit) {
                break;
            } else {
                $count++;
            }
            //...
        }

        if($count > $limit) {
            //keeping these hidden just to store the values 
            $str .= "<input type='hidden' class='nextPage' value='" . ($page + 1) . "'>
                    <input type='hidden' class='noMorePosts' value='false'>";
        } else {
            $str .= "<input type='hidden' class='noMorePosts' value='true'><p style='text-align: centre;'> No more posts to show!</p>";
        }
    }
    //...
}

 

You only loop through your posts until $count = $limit, then you stop.  As such, $count will never exceed $limit so your if ($count > $limit) check later on will always be false, resulting in your code responding with the noMostPosts = true marker.

What you need to do is stop outputting posts when $count > $limit in your loop, but continue to increment count so your code later knows if there are more pages or not.

Link to comment
Share on other sites

On 11/13/2021 at 6:35 PM, kicken said:

You only loop through your posts until $count = $limit, then you stop.  As such, $count will never exceed $limit so your if ($count > $limit) check later on will always be false, resulting in your code responding with the noMostPosts = true marker.

What you need to do is stop outputting posts when $count > $limit in your loop, but continue to increment count so your code later knows if there are more pages or not.

Ok, I understand exactly what you're saying and I thought I addressed this with starting $count = 1. That way after the loop runs 10 times ($limit) than $count = 11 and is therefore > $limit. This is why I'm really lost on it. Even after displaying the first 10 posts it's actually not adding the else string to the end ->

$str .= "<input type='hidden' class='noMorePosts' value='true'><p style='text-align: centre;'> No more posts to show!</p>";

because I'm not seeing 'No more posts to show!' as I do if I change the '>' operator to '<' or '=' or '<=' in the same if statement, for example. So I don't really know where to go from here. I feel my PHP is, at least logically sound, though I know I'm no great coder, and I keep getting my head stuck on the Ajax. Which isn't my code, as I stated before, but I've been studying it and outside the 2 seemingly useless variables height and scroll_top it seems to my very untrained eye it should do something lol. Have I missed something in my PHP logic? I've looked at it 100,000 times

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.