1

I'm working on a historical database with 2,000+ photos that need to be categorized of which about 250 are loaded. I've created a MYSQL database with 26 fields to hold this data.

I'm using PHP to access the database and retrieve the information.

I'd like to use JavaScript to manage the rest of the form. All of the code is in one php file.

The problem I'm running into is when I

//$result is the php associative array holding the photo information

<div id="dom-target" style="display: none;">
     <?php echo json_encode($result); ?>
</div>
<script>
    var div =document.getElementById("dom-target");
    var photo_array = JSON.parse(div.textContent);  

It works but, I get the entire database structure and data embedded in the source html output. Obviously this won't do especially as the photo count increases.

How can I prevent this?

If I were to split this one php file into two, one containing php accessing the database and returning an array, and the other page containing all of the input boxes etc., and use AJAX passing the array as a JSON; would that work? I'd hate to go down that path unless it'll be successful. I've read where you can't pass the array if all of the code is on one page.

Or, should I just stick with doing everything in php?

Thanks, Eric

Edit: What I want to do is to pass a php array to js without having all of the data in the array included in the source. By source I mean when someone "views source". I also think that once I get up to 2,000 photos is is going to be unwieldy....(2,000 photos) x (26 fields) = a lot of stuff needlessly included in the web page.

I have no objection to using AJAX. But all of the examples I've seen have the request on one page and the response on another. Do I need to split up my code onto two pages; one to handle the php and MySQL and the other to handle the html and js?

What I envision is a screen showing the selected photo at 800x600 with the input fields below that. A person enters the title, caption, description etc and that is saved in the db with the photo's name. Below that I would have 20 thumbnail photos which a person could pick from to enter that photo's information. I would loop through the database 20 or so, photos at a time. Only the file names are stored in the database, the actual photo jpg is stored on a hard disk and retrieved via an statement.

How can I do this without all of the data in the database array being on the html source page?

Edit 2: I've been asked to include more of my php. Sorry I couldn't make it neater.

<?php
$stmt_select->bind_result(
     $select_array['fhs_pkey'], 
     $select_array['file_name'],
     $select_array['caption'],  
     $select_array'post'],
     $select_array['photo_type'], 
     $select_array['last_name'], 
     $select_array['first_name'], 
     $select_array['middle_name'], 
     $select_array['honorific'], 
     etc., etc., etc
);

// put all of the database info into an array. Filename field is for full size photos
$j=$stmt_select->num_rows;
for ($i=0;$i<$j;$i++)
{
    $stmt_select->data_seek($i);
    $row = $stmt_select->fetch();
    //put all of the column data into the array
    foreach ($select_array as $key=>$value)                   
        $result[$i][$key]=$value;

    //in a separate php file resize the photos and save them
    //put full path with appended filename to retrieve later                  
    $result[$i]['resized'] = 
        "../images/fhs_images/800x600_photos/800x600--" .
        $result[$i]['file_name'] ;
    $result[$i]['thumb'] = "../images/fhs_images/200x150_photos/200x150--" .
        $result[$i]['file_name'] ;

} 
$stmt_select->close();
$stmt_update->close();
$stmt = null;
$conn = null;

echo '<figure id="photo_figure">';
$filename = $result[2]['resized'];
echo "<img src = "."'".$filename."'" ."/>";

?>

<script>
//below is where I get the entire array printed out when I view source          
var photo_array = <?php echo json_encode($result); ?>      
var testing = photo_array[40]['thumb'];
//take care of spaces in filenames
testing = encodeURI(testing)

document.write('<img src=' + testing + '>')
</script>                 

Edit 3 @trincot

Something's not right. I moved all of my MYSQL db setup and retrieve into a new file called fhs_get_photos.php. In my jQuery ready function I added the below. See my comments on what gets displayed

var myarray;
$(document).ready(function()
{
$('.tooltips').powerTip();

$(".radio1").on('click',(function()
    {
        var photo_type = $("input[name='photo_type']:radio:checked").val();
        if(photo_type == 2)
            $(".person").hide();
        else
            $(".person").show();

    }));


 $.getJSON("fhs_get_photos.php", function(photo_array)
 {
    if (photo_array.jsonError !== undefined) 
    {
      alert('An error occurred: ' + photo_array.error);
      return;
    }

    // photo_array now contains your array. 
    // No need to decode, jQuery has already done it for you.
    // Process it (just an example)
    //$.each(photo_array, function(i, obj){
    //    $("#dom-target").append(obj.fhs_pkey + " " + obj.file_name + ", ");

//this displays correctly on a screen but not with anything else.
//Seems as if it's rewriting the page and only this is displaying which 
//may be how it's supposed to go
document.write("In js. photo_array 2,caption is: " + photo_array[2]     ['caption']);   
    });

});

In my main php I put

       document.write("photo_array 2,caption is: " + photo_array[2]['caption']);    

but it's not displaying anything. I suspect photo_array is not being passed into the page. In the js file, I then created a global variable 'myarray' and in the .getJason function I added

 myarray = photo_array;

thinking it would pass into the main file but it didn't.

eric
  • 281
  • 1
  • 6
  • 17
  • If you want to pass data - you need to pass data. Switching to AJAX does not reduce amount of data. – zerkms Feb 10 '16 at 23:17
  • Sorry, but can you explain exactly what the goal is, aside from how you are attempting to achieve it. –  Feb 10 '16 at 23:17
  • the ajax way will work i used it before actually but you need to be good in handling ajax response to pull this off – FareedMN Feb 10 '16 at 23:18
  • What is the reason you don't want to use AJAX? It is actually quite simple, with jQuery at least. – BoltKey Feb 10 '16 at 23:19
  • You need to clarify (or perhaps describe to us) how the user interface *works*. If you load 250 images in a HTML page, then the overhead of having JSON metadata in the HTML is negligible, and @trincot 's answer is definitely the way to go. If, on the other hand, you want to implement something akin to paging, perhaps with even smaller pages (say 20 images each), an AJAX service would be an easy and approachable alternative to reloading the page with a different image offset in the database (which is doable too). – LSerni Feb 10 '16 at 23:26
  • @BoltKey I have no objection to using AJAX; I'll use whatever is best. I just need to find a way to pass that array from php to js without the entire string showing up in my source. – eric Feb 11 '16 at 15:16
  • "Long talk about MVC young padawan needs." ... just go for ajax, it's something trivial nowadays and should be in everybody's utility belt. What you want is a php that spits out the data but only answers to post requests. If you don't have a router (I suppose you don't have one) you must filter the request and then spit out the json data. – SparK Feb 12 '16 at 15:03

1 Answers1

3

There are in principle two ways you can think of to get data in JavaScript:

1. Ajax request

With this solution use your current PHP file for generating the HTML page only, so without generating JSON, and create another PHP file which will generate the JSON only.

So let's say your JSON-generating PHP file is called fhs_get_photos.php, then it would have this code (no HTML!):

<?php
header("Content-Type: application/json");

// Collect what you need in the $result variable.
// ...
// and then:

echo json_encode($result);

?>

See the last section in my answer for treating JSON encoding errors.

Make sure there are no line breaks or spaces before the opening <?php, and that you do not echo or print anything else than that one JSON string.

Your database query would also be in this new file. Note that currently you have a mix, like with this line:

echo "<img src = "."'".$filename."'" ."/>";

This line belongs in the non-JSON file, but it also depends on the query. So either you make an include file that does the query, include it in both PHP files, or you move the logic of defining the image tag (or at least the image's source) to the JavaScript part (better!).

Then in the original PHP file, remove the JSON output, and add some JavaScript, using jQuery (I understood you were already using it, so you have it included):

$(function(){
    $.getJSON("fhs_get_photos.php", function(photo_array){
        // photo_array now contains your array. 
        // No need to decode, jQuery has already done it for you.
        // Process it (just an example)
        $.each(photo_array, function(i, obj){
            $("#dom-target").append(obj['fhs_pkey'] + " " + obj['file_name'] + ", ");
        });
        // or things like:
        $("#caption_input").val(photo_array[2]['caption']);
    });
}); 

This function will get executed once the HTML DOM has been built, so evidently after the first PHP file has finished execution. It will make the request to the second PHP file. Once that request is answered by PHP, the inner call-back function will receive the data. Note that there is no need to decode JSON here, as jQuery has already done that for you.

2. Generate JavaScript with data

Here you keep your current PHP file, but move the part where you inject the JSON encoded data to the JavaScript block:

    <script>
        var photo_array = <?php echo json_encode($result); ?>;
        // ... process it
    </script>

There is no need to wrap JSON in a JavaScript string to then parse it.

From json.org:

JSON is a subset of the object literal notation of JavaScript. Since JSON is a subset of JavaScript, it can be used in the language with no muss or fuss.

2.1. Valid JSON that could be invalid JavaScript?

Although not a problem in the context of this question (see below), there is an incompatibility between JSON and JavaScript syntax. It concerns whether or not the non-ASCII characters U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are allowed to appear unescaped in quoted strings:

  • JSON syntax allows this, as stated in the ECMAScript® 2015 Language Specification, section 24.3.1:

    JSON allows Unicode code points U+2028 and U+2029 to directly appear in String literals without using an escape sequence.

  • JavaScript syntax does not allow this, as indicated in the ECMAScript® 2015 Language Specification, section 11.8.4:

    All code points may appear literally in a string literal except for the closing quote code points, U+005C (REVERSE SOLIDUS), U+000D (CARRIAGE RETURN), U+2028 (LINE SEPARATOR), U+2029 (PARAGRAPH SEPARATOR), and U+000A (LINE FEED). Any code points may appear in the form of an escape sequence.

PHP's json_encode however, follows the possibility offered in that last line, and escapes all non-ASCII characters, including the problematic U+2028 and U+2028, except if you explicitly tell PHP not to do so with the JSON_UNESCAPED_UNICODE flag:

JSON_UNESCAPED_UNICODE (integer)

  • Encode multibyte Unicode characters literally (default is to escape as \uXXXX). Available since PHP 5.4.0.

So, a json_encode call without this flag will not produce instances of this problem.

3. Catch json_encode failures

According to the manual on json_encode the method can return a non-string (false):

Returns a JSON encoded string on success or FALSE on failure.

When this happens echo json_encode($result) will output the empty string, which is invalid JSON.

This error condition should be captured in PHP, for example like this:

<?php
header("Content-Type: application/json");

// Collect what you need in the $result variable.
// ...
// and then:

$json = json_encode($result);
if ($json === false) {
    $json = json_encode(array("jsonError", json_last_error_msg()));
    if ($json === false) {
        // This should not happen, but we go all the way now:
        $json = '{"jsonError": "unknown"}';
    }
}
?>

And then in JavaScript, this condition should be handled as well, for example like this:

if (photo_array.jsonError !== undefined) {
    alert('An error occurred: ' + photo_array.jsonError);
    return;
}
Community
  • 1
  • 1
trincot
  • 317,000
  • 35
  • 244
  • 286
  • "JSON is a subset of Javascript" --- well, it's not. Not every valid JSON is a valid JS. – zerkms Feb 10 '16 at 23:18
  • Definitely, in js, `a = "[1, 2, 3]"` and `a = [1, 2, 3]` are different things. It is needed to parse. – BoltKey Feb 10 '16 at 23:21
  • Thanks, @zerkms, I put a more exact quote from json.org instead. – trincot Feb 10 '16 at 23:21
  • @BoltKey, the double quotes are not there. Correct JSON starts with either a `{` or a `[`, but not a double quote. – trincot Feb 10 '16 at 23:21
  • @trincot well, that quote does not mean you can safely use any JSON in JS as-is. Check the http://stackoverflow.com/q/23752156/251311 for further details. – zerkms Feb 10 '16 at 23:27
  • Oh yeah, you are right. I somehow messed it up with AJAX requests in my head and got totally confused. Gosh, I should go sleep and stop making idiot of myself on StackOverflow. – BoltKey Feb 10 '16 at 23:32
  • I read that, @zerkms, but it seems quite a rare circumstance. I cannot reproduce it anyway. This works for me: `var x = {"key":"It's\u2028ok"};`. Also, the statement of json.org does not make sense if you still have to call an API to decode it. – trincot Feb 10 '16 at 23:37
  • Try this `{"JSON":"ro
cks!"}` – zerkms Feb 10 '16 at 23:41
  • @zerkms, I get that as a normal space (\u0020). Maybe SO translated it? – trincot Feb 10 '16 at 23:48
  • It has not: if I copy-paste it to console I get the exception. Here is fiddle: https://jsfiddle.net/kxxq83yL/ – zerkms Feb 10 '16 at 23:49
  • "Also, the statement of json.org does not make sense if you still have to call an API to decode it." --- ¯\_(ツ)_/¯ – zerkms Feb 10 '16 at 23:51
  • I saw the fiddle, thanks! I put this in PHP, and see that PHP `json_encode` does not generate such JSON, but escapes it to `\u2028`. In my understanding this particular problem will not occur in combination with the PHP code at hand. – trincot Feb 10 '16 at 23:56
  • @trincot yep, if the encoder/serialiser takes care of it - it would be fine. But to be 100% precise one must not say JSON is a subset of JS. PS: sorry for being annoying though :-) – zerkms Feb 11 '16 at 00:01
  • trincot....that did not work. I still end up with ....... (my database structure with the data) showing up in the page's source. – eric Feb 11 '16 at 15:08
  • What you call *my database structure with the data* is JSON. It is what is intended to appear there. Does your Javascript code break? Do you do anything with that variable `photo_array` ? – trincot Feb 11 '16 at 15:24
  • @trincot I do not want it there. I would use a row of that data to populate text/input boxes. If the caption of the photo was "Barn" then photo_array[x]['caption'] data would be in the caption text box. (Not used to enter key submitting) The js code does not break. – eric Feb 11 '16 at 15:34
  • OK, now you lost me. You write in the question update *"What I want to do is to pass a php array to js without having all of the data in the array"*. There is no way you can pass data to JS and not have it in ... the JS script, which can always be retrieved by the user. I think you need to rethink this. First determine exactly which part of the data is needed on the actual web page your are going to show. I suppose you are not going to show 2000 photos, right (if so, it will not be my favourite website :-). So in PHP you have to first limit the data for what really is needed, and then JSON it. – trincot Feb 11 '16 at 15:58
  • @trincot sorry about that. I want to pass a php array (w/data) to js (w/data) but not have all of the data show up in the html source. No images are included in the array only their file names. I will only be showing 20 or so thumbnail photos at a time so will it be one of your favorite sites? :-) I'm getting the feeling that I can not pass data from php to js w/o the data being included and displayed when a user 'View's Source' on the page, so I'll stick with php for it all. – eric Feb 11 '16 at 16:10
  • The alternative is AJAX, but it requires a bit of redesign. I can add that to my answer, but could you then please add a bit more of your current PHP code to have a bit more of context? I will prepare an answer and post it later. Are you willing to use the jQuery library in Javascript? – trincot Feb 11 '16 at 16:13
  • @trincot I have jQuery included already. Ok, I'll put more php in my questions although most of it is setting variables, prepared statements etc I'll put from where I'm selecting. I definitely appreciate your help. Next time you're in the Syracuse NY area look me up and I'll buy you a few beers :-) – eric Feb 11 '16 at 16:26
  • Added a draft answer (point 1), which conveys the idea on how to do it. My previous answer is under point 2. – trincot Feb 11 '16 at 16:50
  • @trincot Thanks. I'm going to be a bit jammed up but will implement your solution by Sunday. – eric Feb 11 '16 at 22:30
  • @trincot I added Edit 3. Basically it's not working as intended. – eric Feb 12 '16 at 14:59
  • Don't do `document.write`... ever. For debugging use `console.log(...);`. The correct syntax you need is `$("#caption_input").val(photo_array[2]['caption']);`. Note also slight correction I made in the JS error checking code (property name is jsonError, not error). – trincot Feb 12 '16 at 15:22
  • @trincot yes, I caught that about a minute ago. It seems as if the rest of the program logic stays within the jQuery ready function since I can't get the array to the main page? I'm kind of new to jQuery and AJAX so I appreciate your patience with a newbie :-) – eric Feb 12 '16 at 15:53
  • You can assign `photo_array` to a global JS variable, but be aware that this assignment is only executed when you get a reply from your AJAX call. So don't expect your global variable to already have the data during page load. It will only be there later ([read about this](http://callbackhell.com/)). – trincot Feb 12 '16 at 16:07