From PHP/MySQL/JSON to iOS/Objective-C/SQLite - php

I'm trying to create an iOS application which upon loading, will initially connect via HTTP back to a PHP web service which will output data as JSON from a MySQL database. I would then like it to import this data into a local SQLite database within the iOS app. I've already downloaded the JSON-Framework for Objective-C.
My question is two fold.
1) What is the best way to output the JSON from PHP so that I can send multiple database tables in the same JSON file? I have 4 tables of data that I'm trying to send (user, building, room, device).
Here is how I am currently outputting the JSON data:
// Users
$query = "SELECT * from user";
$result = mysql_query($query,$conn) or die('Errant query: '.$query);
$users = array();
if(mysql_num_rows($result)) {
while($user = mysql_fetch_assoc($result)) {
$users[] = array('user'=>$user);
}
}
// Buildings
$query = "SELECT * from building";
$result = mysql_query($query,$conn) or die('Errant query: '.$query);
$buildings = array();
if(mysql_num_rows($result)) {
while($building = mysql_fetch_assoc($result)) {
$buildings[] = array('building'=>$building);
}
}
// Rooms
$query = "SELECT * from room";
$result = mysql_query($query,$conn) or die('Errant query: '.$query);
$rooms = array();
if(mysql_num_rows($result)) {
while($room = mysql_fetch_assoc($result)) {
$rooms[] = array('room'=>$room);
}
}
// Devices
$query = "SELECT * from device";
$result = mysql_query($query,$conn) or die('Errant query: '.$query);
$devices = array();
if(mysql_num_rows($result)) {
while($device = mysql_fetch_assoc($result)) {
$devices[] = array('device'=>$device);
}
}
header('Content-type: application/json');
echo json_encode(array('users'=>$users));
echo json_encode(array('buildings'=>$buildings));
echo json_encode(array('rooms'=>$rooms));
echo json_encode(array('devices'=>$devices));
I fear that this method isn't the right way to send multiple objects.
2) In the iOS app, how can I automatically take this JSON data and insert it into the corresponding local database tables in SQLite?
Thanks for any help.

On 1. Instead of JSOn you could use binary Property lists they are natively implemented on the iPhone and there is a library to turn PHP into binary Plist https://github.com/rodneyrehm/CFPropertyList
There are many benefits to using binary property lists, they are probably 1/5 of the size of JSON, you don't need a external library to parse them, therefore all code is much simpler, etc.
On 2. There is no easy way to take the JSON/Plist structure and insert it to a SQL database, because JSON/Plist allow much more flexibility then SQL tables. So you would have to first create the right tables in your SQLite DB and then use normal INSERT to insert the data one by one into the database exactly like you would do with PHP.

Yeah Luke's recommendation is good but you will be fine with the way you are exporting your tables. You may just have to dig "deeper" into the structure to get what you want - i.e. your output with return a "dictionary of dictionaries of arrays" which will then contain the data for each table.
As for downloading them first:
1) NSURLConnection and its delegate methods - you can send asynchronous request to your webserver to get this file and get notified when the data has been downloaded so the user interface is never blocked in your app.
Here's the documentation with some good examples from Apple: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
At the end of the download, you will have an NSData object which can then be converted back to a string using NSString *jsonContents = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding.
You can then use a JSON parser library - I recommend SBJSON https://github.com/stig/json-framework - which will parse the data and return it as a dictionary or array depending on your structure.
From there you can access your tables and value with valueForKey in dictionaries or objectAtIndex: in arrays and then map it into your chosen local storage, for which I recommend Coredata (or you could use sqlite if you are familiar with it too).
Hope it helps.
Rog

I can't speak to 2), but for 1), I would recommend combining your JSON into a single array. One of the nice things about JSON (and arrays) is the ability to nest elements as deeply as you like.
echo json_encode(array(
'users'=>$users,
'buildings'=>$buildings,
'rooms'=>$rooms,
'devices'=>$devices,
));

What about preparing the SQLite database on the webserver and downloading that to the iOS application? This way, you do the heavy lifting on the PHP side. If the data is relatively static, you can even setup a scheduled task to generate the SQLite database on a regular interval.
We've done this for one of our apps and it worked very well.
One thing to keep in mind then is that you should enable gzip compression on the webserver to minimize the data transfer. Remember that you have to do some extra stuff to use gzip compression with NSURLConnection:
http://www.bigevilempire.com/codelog/entry/nsurlconnection-with-gzip/

you can use REST server and RESTKit.

If you would like a more full-featured solution that what is offered by a standalone parsing library, you may want to take a look at RestKit: http://restkit.org/
The framework wraps the operations of fetching, parsing, and mapping JSON payloads into objects. It can handle deeply nested structures and can map directly back to Core Data for persistence.
At a high level, here's what your fetch & post operations would feel like in RestKit:
- (void)loadObjects {
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[#"/path/to/stuff.json" delegate:self];
}
- (void)objectLoader:(RKObjectLoader*)loader didLoadObjects:(NSArray*)objects {
NSLog(#"These are my JSON decoded, mapped objects: %#", objects);
// Mutate and PUT the changes back to the server
MyObject* anObject = [objects objectAtIndex:0];
anObject.name = #"This is the new name!";
[[RKObjectManager sharedManager] putObject:anObject delegate:self];
}
The framework takes care of the JSON parsing/encoding on a background thread and let's you declare how attributes in the JSON map to properties on your object. A number of people in the community are working with PHP backends + RestKit with great success.

Related

PHP API for android using mysql

So, currently i am using firebase for storing my app data online,
I would like to create my own database,
so i was planning to get a 100gb bandwidth hosting plan with php and mysql (is that bandwidth enought) per download, my app downloads approximately 0.4MB of data (as per firebase).
So, to create the api, i just have to encode the mysql data into json and print it ? then my android app will read it and use it ? is this the best method ?
$sth = mysqli_query("SELECT ...");
$rows = array();
while($r = mysqli_fetch_assoc($sth)) {
$rows[] = $r;
}
print json_encode($rows);
or is there any other, more efficient method to do this ?
Yes but you should send response code like 200,403 as well.
here is a similar question
How to write a REST API?

parsing paginated json from web service

I am trying to parse a large amount of JSON data generated from a remote web service. The output produced is paginated across 500 URIs and each URI contains 100 JSON objects. I need to match a property in each JSON object, it's DOI (a digital object identifier), against a corresponding field fetched from a local database and then update the record.
The issue I am having is controlling my looping constructs to seek out the matching JSON DOI while making sure that all the data has been parsed.
As you can see I have tried to use a combination of break and continue statements but I am not able to 'move' beyond the first URI.
I later introduced a flag variable to help control the loops without effect.
while($obj = $result->fetch_object()){
for($i=1;$i<=$outputs_json['meta']['response']['total-pages'];$i++){
$url = 'xxxxxxxxxxxxxxx&page%5Bnumber%5D='."$i".'&page%5Bsize%5D=100';
if($outputs = json_decode(file_get_contents($url),true)===false){
}
else{
try{
$outputs = json_decode(file_get_contents($url),true);
$j=0;
do{
$flag = false;
$doi = trim($outputs['data'][$j]['attributes']['identifiers']['dois'][0], '"');
if(!utf8_encode($obj->doi)===$doi) continue;
}else{
$flag = true;
$j++;
}
}while($j!==101);
if($flag===true) break;
} catch(Exception $e) {
}
}
}
}
}
What is the optimal approach that guarantees each JSON object at all URIs is parsed and that CRUD operations are only performed on my database when a fetched record's DOI field matches the DOI property of the incoming JSON data?
I'm not 100% sure I understand every aspect of your question but for me it would make sense to change the order of execution
fetch page from external service
decode json and iterate through all 100 objects
get one DOI
fetch corresponding record from database
change db record
when all json-objects are progressed - fetch next url
repeat until all 100 urls are fetched
I think it's not a good idea to fetch one record from local DB and try to find it in 100 different remote calls - instead it's better to base your workflow/loops on fetched remote data and try to find the corresponding elements in your local DB
If you think that approach will fit your task - I can of course help you with the code :)

Cache data from MySQL in PHP?

Is it possible to ask for all data in my database and make objects from it and save it into an array or something, so I just need to call the database once and afterwards I just use my local array? If yes, how is it done?
public function getAllProjects(){
$query="SELECT * FROM projects";
$result=mysql_query($query);
$num=mysql_numrows($result);
while ($row = mysql_fetch_object($result)) {
// save object into array
}
}
public function fetchRow($row){
include("Project.php");
$project = new Project();
$id=$row->id;
$project->setId($id);
$title=$row->title;
$project->setTitle($title);
$infos=$row->info;
$project->setInfo($infos);
$text=$row->text;
$project->setText($text);
$cate=$row->category;
$project->setCategory($cate);
return $project;
}
If I have for example this code. How do i store the objects correctly into an array, where I grab the data from? And why can't I make more than one object of type "Project"?
Let's ignore the fact that you will run out of memory.
If you have everything in an array you will no longer have the functionalities of a relational database.
Try a search over a multi megabytes, multi dimensional array in php and be prepared for a extended coffee break.
If you are thinking in doing something like that is because you feel that the database is slow... You should learn about data normalization and correct use of indexes then.
And no NoSQL is not the answer.
Sorry to pop your balloon.
Edited to add: What you CAN to is use memcache to store the final product of some expensive processes. Don't bother storing the result of trivial queries, the internal cache of mysql is very optimized for those.
You should use the $_SESSION vars in php, To use them, add a session_start() at the beginning of your code. Then you can set vars with $_SESSION['selectaname'] = yourvar
Nothing prevent you to make a sql query like "SELECT username FROM users WHERE id = 1" and then set a $_SESSION['user'] = $queryresult
Then you'll have this :
echo $_SESSION['user'];
"mylogin"

memcaching php resource objects

Say I have this code in PHP :
$query = mysql_query("SELECT ...");
the statement returns a resource object. Normally it would get passed to mysql_fetch_array() or one of the mysql_fetch_* functions to populate the data set.
I'm wondering if the resouce object - the $query variable in this case can be cached in memcache and then a while later can be fetched and used just like the moment it's created.
// cache it
$memcache->set('query', $query);
// restore it later
$query = $memcache->get('query');
// reuse it
while(mysql_fetch_array($query)) { ... }
I have googled the question, didn't got much luck.
I'm asking this is because it looks way much light-weighted than the manner of "populate the result array first then cache".
So is it possible?
I doubt it. From the serialize manual entry
serialize() handles all types, except the resource-type.
Edit: Resources are generally tied to the service that created them. I don't know if memcached uses serialize however I'd guess it would be subject to the same limitations.
The Memcache extension serializes objects before sending them to the Memcached server. As the other poster mentioned, resources can't be serialized. A resource is basically a reference to a network connection to the database server. You can't cache a network connection and reuse it later. You can only cache the data that gets transmitted over the connection.
With queries like that, you should fetch all rows before caching them.
$all_results = array();
while ($row = mysql_fetch_array($query)) {
$all_results[] = $row;
}
$memcache->set('query', $all_results);
Modern database drivers such as MySQLi and PDO have a fetch_all() function that will fetch all rows. This simplifies things a bit.
When you retrieve that array later, you can just use foreach() to iterate over it. This doesn't work with very large query results (Memcached has a 1MB limit) but for most purposes you shouldn't have any problem with it.

AS3 and mySQL or XML: Saving user votes on server from a flash movie

A project of mine involves a flash movie (.swf) in a webpage, where the user has to pick from a number of items, and has the option to thumbs up or thumbs down (vote on) each item.
So far I have gotten this to work during each run of the application, as it is currently loading the data from an XML file - and the data is still static at the moment.
I need to persist these votes on the server using a database (mySQL), such that when the page is reloaded, the votes aren&apos;t forgotten.
Has anyone done this sort of thing before?
The two mains methods that I have found on the &apos;net are
either direct communication between AS3 and the SQL using some sort of framework, or
passing the SQL query to a PHP file, which then executes the SQL query and returns the SQL to AS3.
Which of these methods is the better option?
For the latter method (involving PHP), I have been able to find resources on how to acheive this when attempting to retrieve information from the database (i.e. a read operation), but not when attempting to send information to the database (i.e. a write operation, which is needed when the users vote). How is this done?
Thank you!
Edit: Implemented solution
Somewhere in the PHP file:
if ($action == "vote")
{
$id = $_POST['id'];
$upvotes = $_POST['upvotes'];
$query = "UPDATE `thetable` SET `upvotes` = '$upvotes' WHERE `thetable`.`id` = '$id' LIMIT 1 ;";
$result = mysql_query($query);
}
Somewhere in the ActionsScript:
public function writeToDb(action:String)
{
var loader:URLLoader = new URLLoader();
var postVars:URLVariables = new URLVariables();
var postReq:URLRequest = new URLRequest();
postVars.action = action;
postVars.id = id;
postVars.upvotes = upvotes;
postReq.url = <NAME_OF_PHP_FILE>;
postReq.method = URLRequestMethod.POST;
postReq.data = postVars;
loader.load(postReq);
loader.addEventListener(Event.COMPLETE, onWriteToDbComplete);
}
I am not aware of any framework that supports method-1.
I would use method-2 - but instead of making the query within Flash and passing it to PHP, I would rather pass the related data and construct the query in PHP itself. This is safer because it is less susceptible to SQL injection attacks.
This answer has an example of sending data from flash to the server - it talks about ASP, but the method is same for PHP (or any technology) - just change the URL.
Within the php code, you can read the sent data from the post $_POST (or $_GET) variable.
$something = $_POST["something"]
Many different options:
AMFPHP - binary messaging format between PHP and Actionscript/Flash.
LoadVars - for POSTing and GETing values to a PHP script.
JSON - Using the AS3Corelib you can post JSON formatted data to your web site (just like an AJAX script does).

Categories