-1

So, I have a website that hits up a very simple PHP script to display data from a database in an HTML table.

My question is simple; is it possible to write the PHP script in such a way that I can use the same script to get the same data and return it in JSON for the android app that will need it (without a single if(onMobileApp) type god statment which is basically equivalent to writing two scripts anyways)?

Or do I have to have two scripts, like

get_songs_web.php
get_songs_android.php

It should be noted that speed of development is crucial here; I'm learning this skill for a 24h competition, so I'm writing procedural PHP, not OO.

As an example of the type of scripts I have, so that you can use it as an example in your responses, here is one of the ones used in the webpage:

<?php
    // Connect to database
    $db_connection = mysqli_connect('localhost', 'root', '', 'songs_list_data')
    or die('Error connecting to MySQL server!');

    // Get data from HTML form
    $name = $_POST["song"];
    $artist = $_POST["artist"];

    // Add song to database
    $add_song_query = $db_connection->prepare("INSERT INTO songs"
            . "(artist, name)"
            . "VALUES (?, ?)");
    $add_song_query->bind_param("ss", $artist, $name);
    $add_song_query->execute();
    $add_song_query->close();
?>

<html>
    <table id="results">
        <?php
            $results_query = $db_connection->prepare("SELECT *"
                    . "FROM songs");
            mysqli_stmt_execute($results_query);
            $result = mysqli_stmt_get_result($results_query);
            $row_num = 1;
            while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) 
            {
                echo '<tr class="songs_table_row">';
                    echo '<td class="row_num">' . $row_num . '</td>';
                    echo '<td class="artst">' . $row['artist'] . '</td>';
                    echo '<td class="name">' . $row['name'] . '</td>';
                echo '</tr>';
                $row_num++;
            }
            mysqli_stmt_close($results_query);
        ?>
    </table>
</html>

<?php
    // Close database connection
    mysqli_close($db_connection);
?>
Bassinator
  • 1,443
  • 2
  • 18
  • 42
  • _is it possible to write the PHP script in such a way that I can use the same script to get the same data and return it in JSON_ **Answer = YES** – RiggsFolly Mar 29 '17 at 15:36
  • If you don't have code after

    Remove the mysqli_close it's useless (it's auto closed at the end of the script).

    – neoteknic Mar 29 '17 at 15:38
  • @RiggsFolly Well, yeah. I figured it was. Better phrasing would've been *how*? – Bassinator Mar 29 '17 at 15:38
  • In your question your write `[...]without a single if(onMobileApp) type god statement[...]`. But in the accepted answer the `if( preg_match(...) )` is an `if(onMobileApp)`, was your question just about how to replace the `while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) ` that uses `echo` with a loop that fills an array? – t.niese Mar 29 '17 at 16:28
  • It was done slightly more elegantly in the answer. If you have a better way, I'm curious. – Bassinator Mar 29 '17 at 16:32

3 Answers3

1

Yes, use

<?php
echo json_encode($your_data);

To export to JSON. Not sure if json_encode is enabled by default in your php version. It's worth a try.

If you need the code to export both JSON and HTML use something like:

<?php

if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
    strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) {

    // ... export JSON here

} else {

    // ... export HTML here

}
Ayse
  • 11
  • 3
  • How could I detect if the user is hitting the page from a mobile app or a website? – Bassinator Mar 29 '17 at 15:34
  • 1
    Set a user agent from mobile app request "Android" and detect the user agent or simply send a get value is_mobile. – neoteknic Mar 29 '17 at 15:36
  • @Airhead If you write the PHP to just return JSON then you shoudl now care where its called from. You just amend the code in the JAVA or PHP or ANYTHING ELSE to use what is returned i.e. JSON in whatever way it wants to that is appropriate for that environment – RiggsFolly Mar 29 '17 at 15:39
  • @RiggsFolly The problem is that a browser cannot display JSON. So, would I not then have to write a script to convert the JSON into HTML, then removing the point of using a single script in the first place? – Bassinator Mar 29 '17 at 15:40
  • @Airhead Yes, but the upshot of using data structures instead of markup language is that you can use the same result for more purposes. You could use the JSON in a website or an app. In a website you could use the JSON to populate a table, a dropdown or an autocomplete feature. If you (only) output HTML you are limited in the use of the result. – Ayse Mar 31 '17 at 08:22
1

Like this?

<?php
$results_query = $db_connection->prepare("SELECT * FROM songs");
mysqli_stmt_execute($results_query);
$result = mysqli_stmt_get_result($results_query);
$row_num = 1;
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) 
{
    $myDataArray[] = array(
        'row_num'   => $row_num,
        'artist'    => $row['artist'],
        'name'      => $row['name'],
    );
    $row_num++;
}
mysqli_stmt_close($results_query);

function displayHtmlTable($dataArray){
    $output = '';
    $output .= '<table>';
    $output .= '<tbody>';
    foreach($dataArray as $rowId => $rowData){
        $output .= '<tr>';
        foreach($rowData as $colId => $cellData){
            $output .= '<td class="' . $colId . '">' . $cellData . '<td>';
        }
        $output .= '</tr>';
    }
    $output .= '</tbody>';
    $output .= '<table>';
    return $output;
}


$useragent = $_SERVER['HTTP_USER_AGENT'];
if(preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',substr($useragent,0,4))){
    header('Content-Type: application/json');
    echo json_encode($myDataArray);
}else{
    echo displayHtmlTable($myDataArray);
}
Bloafer
  • 1,314
  • 7
  • 12
  • Could you explain the `preg_match` bit? – Bassinator Mar 29 '17 at 15:48
  • It matches the User-Agent to detect mobile device http://stackoverflow.com/questions/4117555/simplest-way-to-detect-a-mobile-device it's a quick and easy way to detect mobile but may not be 100% accurate – Bloafer Mar 29 '17 at 15:49
  • Okay, one last thing I want to make sure I understand; how are you inserting data into `$myDataArray[]`; you don't seem to be indexing it; can a single element in a PHP array hold multiple values like you seem to be doing? – Bassinator Mar 29 '17 at 15:53
  • 1
    @Airhead parsing user agent is not reliable. Either use a query parameter `type=json` or the `Accept` header of the request to determin in what form the data has to be send. – t.niese Mar 29 '17 at 15:55
  • 1
    Yes, multidimensional arrays are easy to build in PHP, if you use `[]` this will append to the array – Bloafer Mar 29 '17 at 15:55
  • 1
    I will never understand the agressive downvoters on SO. I have almost 3,000 rep on aviation SE, but a seemingly perfectly legitimate question on SO garners instant downvotes... sigh. If I *knew the answer* I wouldn't have asked the question. Especially when the downvoters don't even leave a reason in the comments, it just goes to show how toxic this site has become. Every other SE site doesn't seem to suffer from this problem. – Bassinator Mar 29 '17 at 15:58
  • I agree, this is why I don't use it anymore, this is my first answer this year, just took a break and thought I'll answer a question – Bloafer Mar 29 '17 at 16:12
1

You should never rely on the user agent to determine if the data should be send as html, json or any other format. The problem with the user agent is that it could vary between OS and Browser versions, the API doing html requests might change the used user agent, ... . E.g. you might accidentally interpret a mobile browser with an App or an App with a browser, and therefore display the content in the wrong format.

One of the following techniques should be preferred:

A. Using rewrite rules

Create a rewrite rule on the server that will map get_songs.html and get_songs.json to get_songs.php and then determine base on the suffix of the request url what kind of data you want to send. That way the suffix will clearly indicate what kind of data is requested.

B. Using the Accept header

If a browser sends a request to the server and expects html as result then the value Accept header will look something like this:

text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

If you request data from you android app then you could set the value of the Accept header to:

application/json

C. Using an url parameter

If none of the above is possible then you should use an url parameter. The the parameter is not present return the default type, if the parameter (e.g. type=json) is available, then return it in the JSON format.


With those techniques you can reliable determine what content type has to be returned.

Based on that information you can use the technique as described in the answer of Bloafer

If you use a technique that returns different data for the same URL, then you should also return the Vary header. With Accept or User-Agent as value depending on what information you use to determine the returned format. Otherwise an intermediate caching proxy might cache only one of the version and return this even if the header changes for a followup request of another client.

Community
  • 1
  • 1
t.niese
  • 32,069
  • 7
  • 56
  • 86