ajax data value to be used in php to store in a json file

I want to track page links by saving them in a json file in the background with out user noticing. I am using jquery .ajax for the front end and trying to send the link value to a php page for insertion into the json file. I can get the value of the link fine on the front end and am using the right code to add to a json file on the back end in php. I just can't seem to get the value of the link to transfer to php and be saved in the json file. I'm also not sure I have the right if condition in the php to start the php code running. http://webdevcei.com/app/track.html
track.php
Julie AndersonInstructorAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

gr8gonzoConsultantCommented:
In your AJAX call, your data should be "self.href", not just "self" and you should redirect() AFTER  you start the AJAX call.
0
Julie AndersonInstructorAuthor Commented:
Thanks gr8gonzo, but still not working. Nothing is being added to the links.json file. Is this what you meant:
<script>
    function theAjax(self) {
        $.ajax({
            url: "track.php",
            type: 'POST',
            dataType: 'json',
            data: {url: self.href}  //added .href
        });
    }
    // click event on body
      $("#homepage-focus a").on("click", function(e) {    
       
        // cancel event and record outbound link
        e.preventDefault();
        e.stopPropagation();
        var self = this;
        alert(self);

        theAjax(self);  //ajax call before redirect
           
        var redirect = function() {
            window.location.href=self.href;
        }
        //call redirect to have link still open
        redirect();

         
      });
    </script>

<?php

 
    $link = json_encode($_POST['url']);    //Do I need json_encode here??
   

    if(file_exists('links.json')) {    //check if json file exists
    $current_data = file_get_contents('links.json'); //store the json file data into variable using file_get_contents function
    $array_data = json_decode($current_data, true); //convert that data into array format with json_decode function
    $extra = array (    //store another array in the variable extra from values brought over from ajax
      'url' => $link
    );
    $array_data[] = $extra;  //extra variable is stored in addition array variable
    $final_data = json_encode($array_data); //take the array and make it json format with json_encode
    if(file_put_contents('links.json', $final_data)) {  //append the new json data into the json file
      echo "it worked";
    }
      else {
      echo "didn't find json file";
      }
    }
 
?>
0
gr8gonzoConsultantCommented:
Okay, so first off, it looks like you tried to clean up the JS a little bit, which is good, but you should be careful about using the word "self" as the name of a variable, since "self" is actually a special term. This isn't really a "broken" problem, but it's good practice to use effective names in your variables. So instead of:

function theAjax(self) {
        $.ajax({
            url: "track.php",
            type: 'POST',
            dataType: 'json',
            data: {url: self.href}  //added .href
        });
    }

Try just:

function theAjax(linkURL) {
        $.ajax({
            url: "track.php",
            type: 'POST',
            dataType: 'json',
            data: {url: linkURL}
        });
    }

...and then instead of passing in the whole element, just pass in the href:

theAjax(self.href);  //ajax call before redirect


Now, onto the broken parts, let's talk about the JSON encoding. You had a question in one of your lines:
$link = json_encode($_POST['url']);    //Do I need json_encode here??

The short answer is no, but you should really understand what you're doing. The process of "serialization" and "deserialization" is all about converting from one format to another (for now, you can also consider them the same as "encoding" and "decoding"). To better explain it, I want you to imagine a bright, shiny apple. Can you see that in your mind? If so, then you've successfully performed a deserialization. Your brain took the written words that describe "a bright, shiny apple" and turned that into a mental picture.

Now let's say that you wanted to share your mental picture with a friend. You cannot just take your own a mental picture and give it to someone else - the mental picture is just not the kind of thing that can be physically shared like that. So if you want someone else to get that same picture, you both have to agree on a way to communicate, and then you figure out a way to describe your mental picture using that means to communicate.

So you could take your mental picture of an apple and then come up with words to DESCRIBE the picture, "a bright, shiny apple" and then write those words down. When you turn that intangible mental picture into tangible words, you're "serializing" the picture. And then you can give the words to someone else, who "deserializes" the words back into their own mental picture.

Now, there are different ways you could describe the picture. You could either write down the words "a bright, shiny apple" or you might actually literally paint or draw what you see in your head. These are simply different ways of serializing/encoding something intangible to something tangible, or different formats. You usually pick the best format that most accurately describes the original object. So reading the words "a bright, shiny apple" might give two different people two different pictures. They might both be thinking of apples, but one might be imagining it as a green apple, and another is imagining it as a red apple. So if you create a painting of your mental picture, then other people will each get the same mental picture in their head when they see your painting.

However, writing the words "a bright, shiny apple" on a scrap of paper takes you 2 seconds and can be stored in a tiny piece of paper, while an accurate painting might take you hours to create and requires a larger canvas.

So there are different advantages/disadvantages to each format, and it's up to you to pick the one that's best suited to your needs. Do you need each item to take up less space at the potential expense of accuracy? Or do you want it to be as exact as possible? Or do you want it to only be in a format that you and a friend can understand (e.g. a secret language)?

In PHP, there are variables like arrays and objects that are sort of like the mental picture of the apple. They are special formats that are inside PHP's brain that cannot be shared or saved as-is. So if you want to save these, you have to serialize them into something that can be stored and communicated easily, which is almost always a string.

XML and JSON and PHP's own internal serialize/deserialize format are 3 different ways that you can serialize objects / arrays into strings, and then later deserialize the strings back into objects / arrays.

Getting back to your question:
$link = json_encode($_POST['url']);    //Do I need json_encode here??

The first thing you have to ask yourself is: "Is the value I'm encoding/serializing an object or an array that requires serialization in order to be stored?" In this case, $_POST["url"] is simply a string, so if you json_encode() a string, then you'll end up with the same string that has double quotes around it, so:
http://helloworld.com
becomes
"http://helloworld.com"
...which is probably NOT what you want, since the double quotes shouldn't really be part of the URL.

Moving onto the next issue, most of your tracking code depends on the file "links.json" to exist:
if(file_exists('links.json')) {
...decode, update, save, etc...
}

So if your links.json file doesn't exist at all, then it never gets created, so none of that code will ever run in order to create the file. I would instead suggest that you start with a blank array, then overwrite that blank array with the values IF the file exists, and then add your new link to the array, and finally save the array, like this:
<?php
if(isset($_POST['url']))
{
  $link = $_POST['url'];

  // Start with a blank array
  $links = array(); 
  if(file_exists('links.json'))
  {
    // If the file exists, overwrite the blank array with the values that are saved
    $links = json_decode(file_get_contents("links.json"), true); 
  }
  
  // Add our new link
  $links[] = array("url" => $link);

  // And update the file
  if(file_put_contents('links.json', json_encode($links))
  {
    echo "it worked";
  }
  else
  {
    echo "didn't find json file";
  }
}
?>

Open in new window


My final comment to you is that this will NOT work very well when you get into situations where you have multiple people that could be clicking on links at around the same time.

Imagine two different people who both click links at the exact same time. PHP runs this process, and both of them read the file of old values at exactly the same time. There are 3 previous stored links in that file, so BOTH processes begin with those 3 links, and then each one adds its own new link, and saves the file. So both of them will end up with 4 links, and then will save the file with those 4 links, even though you really want to capture 3 old + 1 new + 1 new = 5 total links.

This is called a "race condition" problem, because the outcome depends on "who finishes first". You have multiple runners in a race, and the first one to finish the race might save the file first, but the one who finishes last is the final one to save/write the file, so THAT is the 4th link you'll end up seeing.

You can solve this problem in a couple of ways. The first way is to use file locking, where PHP works with the filesystem to place a special "flag" on the file to tell other competing processes to "wait until this flag is removed". So even if 2 processes start at exactly the same time, the first one to get the file lock in place will be able to do its thing, and once it is finished, the file lock is removed, and the 2nd process will begin to do its work (and will be able to see the results from the 1st process).

File locking is easy to implement, but the downside to file locking is that it depends on the filesystem you're using, and it doesn't perform really well at high volumes.

The second way to solve the problem is not to use JSON and files at all, but to instead store the values into a database. One of the huge advantages of database systems is that nearly all of them (pretty much any of the ones you might normally see or hear about) are designed to handle concurrency like this so 1,000 people might be clicking on a link all at the same time and it would perform pretty well if you were running INSERT queries into a database.

Another advantage to the database is that it would far easier to read from in the future once you want to search through the data. With a JSON file, the only way to properly get at ANY of the data is to literally read the whole thing into memory and deserialize it and THEN find the data you're looking for. After enough clicks, your JSON file is going to be huge, and reading and deserializing a 500-megabyte file is going to take a little time. Then it will get to 1 gigabyte, then 2 gigabytes, etc...

As the file grows, it will take your track.php longer and longer to read and deserialize the old values so it can add the new ones in, so your track.php will grow slower and slower and slower over time until it begins timing out completely. This is not an issue with the database.

So in conclusion, if you want to do this, your best bet is really to avoid JSON altogether and use a database. Serialization/deserialization is great when the data is a mostly-fixed size, but when it grows, then you really should be using a database.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Julie AndersonInstructorAuthor Commented:
Thank You Gr8Gonzo! Worked great! Wonderful analogy with serialization and deserialization! I will look into the database idea, but our project is quite small so I doubt it will there will be very many people using it. I appreciated your detailed explanation, it helped a lot.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.