Friday, September 15, 2017

Android Java to Get JSON Data from Server via PHP

The following Android Java codes are based on Android Studio 2.3. In order for Android to obtain information from a server such as the login password verification, the easiest way is to connect to a web server via PHP. Android then establishes a connection to the server through a URL or a link to a PHP script. The following shows the PHP portion of the codes. I named this file testJSON.php:

<?php

 error_reporting(0);
 $all = array();

 if ($_GET['pc'] == "android") { // changed $_POST to $_GET on 30/11/2020
  $all[0] = array("a"=>1,"b"=>2,"c"=>3);
  $all[1] = array("d"=>4,"e"=>5,"f"=>6);
  $all[2] = array("g"=>7,"h"=>8,"i"=>9);
 }

 $encoded = json_encode($all);
 header('Content-type: application/json');
 exit($encoded);

?>


The following will be the codes from the Android Studio side. But before going into the Java coding, one must make sure Android can access to the Internet. This can be achieved by adding the following line in red in the AndroidManifest.xml file.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.example.eric.testjson">

 <application
  android:allowBackup="true"
  android:icon="@mipmap/ic_launcher"
  android:label="@string/app_name"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:supportsRtl="true"
  android:theme="@style/AppTheme">
  <activity android:name=".MainActivity">
   <intent-filter>
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
  </activity>
 </application>
 <uses-permission android:name="android.permission.INTERNET"/>
</manifest>


The following codes are from the main Android Java called MainActivity.java:

package com.example.eric.testjson; // Your package name will be different, there is no need to paste this code to your MainActivity.java file.

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  new grabFromPHPServer(this).execute("android"); // "android" is a parameter that will be passed to doInBackground in grabFromPHPServer Java sub class
 }
}


The following codes are from the Java class called grabFromPHPServer.java. You can create this Java class by right clicking your Java folder.

package com.example.eric.testjson; // you use your own package info, no need to paste this to your java file

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

public class grabFromPHPServer extends AsyncTask<String, Void, String> {

 private Context context;

 public grabFromPHPServer(Context context) {
  this.context = context;
 }

 protected void onPreExecute() {

 }

 @Override
 protected String doInBackground(String... arg) {

  String passcode = arg[0];
  String link;
  String data;
  BufferedReader bufferedReader;
  String result;

  Log.d("result","start trying to grab from PHP server...");
  try {
   Log.d("result","preparing parameter sent to server...");

   data = "?pc=" + URLEncoder.encode(passcode, "UTF-8");

   link = "http://www.yourOwnURL.com/testJSON.php"+data;
   URL url = new URL(link);
   HttpURLConnection con = (HttpURLConnection) url.openConnection();
   Log.d("result","connection response: "+con.toString());

   bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
   //result = bufferedReader.readLine(); // commented out and replaced with the following on 30th of November 2020
   String strLine;
   while ((strLine = bufferedReader.readLine()) != null)
   {
      if (!strLine.isEmpty()) {
         result += strLine;
      }
   }

   Log.d("result",result.toString()); // spit all JSON data received

   String jSONString = result;
   if (jSONString != null) {
    Log.d("result", "jSON received: "+jSONString.toString());
    JSONArray jsonArr = new JSONArray(jSONString);
    JSONObject query_result = jsonArr.getJSONObject(0);
    Log.d("result", "a->"+query_result.getString("a"));
    query_result = jsonArr.getJSONObject(1);
    Log.d("result", "e->"+query_result.getString("e"));
    query_result = jsonArr.getJSONObject(2);
    Log.d("result", "g->"+query_result.getString("g"));
   }
   else {
    Log.d("result", "jSON received is null");
   }
   return result;
  } catch (Exception e) {
   Log.d("result","grab failed");
   return new String("Exception: " + e.getMessage());
  }
 }

 @Override
 protected void onPostExecute(String result) {
  // you can also process your jSON here
 }
}


AsyncTask extension is crucial in the Java class as it is quite meaningless if you run the connection in your main activity Java class as the connection takes time and you will get an exception error if the JSON data failed to be received within a short period of wait time. But in order to use AsyncTask extension, you need to create a sub class to handle background tasks such as this grabFromPHPServer.java sub class. Please also replace yourOwnURL with your own domain name where your PHP file resides.

The following is the screen shot I took from my Android Monitor. The log is filtered with the keyword 'result' so that I only see output from my very own Log.d results:

Read More »

Monday, August 28, 2017

Javascript to Limit HTML Width for Mobile Devices of Any Orientation

The viewport parameter in the HTML Meta Tag is used to limit the screen width. Another thing to pay attention for these codes is the neccessity to differentiate between tablets and phones. Phones tend to have less resolution whereas tablets can have resolutions comparable to that of PC or Mac. I use a simple criteria to differentiate the two by checking the screen width whether it is wider than 700 pixels. If so, tablets' width will be forced to limit to only 700 pixels. For non-tablets, the width will be limited to the native screen width found in the Javascript system parameter screen.width. Pay attention to when orientation changes. Android will have the width and height paramters swapped whereas the mobile Safari will have the same width and height irregardless of the orientation.

The <body> onorientationchange is used to listen to the orientation change even. Whenever it is fired, the 'content' meta will be reconfigured according to the orientation status. Javascript's window.orientation is used to check the current orientation status in terms of degrees.

Let's jump into the codes:

<html>
<head>
<title>Javascript to Limit HTML Width for Mobile Devices of Any Orientation</title>

<script>

var mobile = navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/iPhone|iPad|iPod/i) || navigator.userAgent.match(/Opera Mini/i) || navigator.userAgent.match(/IEMobile/i);

var safari = navigator.userAgent.match(/iPhone|iPad|iPod/i) && navigator.userAgent.match(/Safari/i);

var ot = ""; // variable "orientation" is used by mobile browsers
if (safari) {
 if (window.orientation == 0) { ot="portrait"; } else { ot="landscape"; }
}
else {
 if (screen.width<screen.height) { ot="portrait"; } else { ot="landscape"; }
}


if (mobile) {
 var mobileWidth = getMobileWidth();
 alert("setting the width of "+mobileWidth);
 document.write('<meta id="vp" name="viewport" content="width = '+mobileWidth+', initial-scale=1.0">');
}
// if it is not mobile, viewport is not supported or will be ignored

function getMobileWidth() {
 var width;
 var isTablet = 0;
 if (safari) { // safari screen width and height remain constant irregradless of the orientation
  if (ot == "portrait") { width = screen.width; if (width>400) {isTablet=1;} }
  else { width = screen.height; if (width>700) {isTablet=1;} }
 }
 else {
  width = screen.width;
  if (ot == "portrait") { if (width>400) {isTablet=1;} }
  else { if (width>700) { isTablet=1;} }
 }
 if (isTablet) {
  if (ot == "portrait") {
   return 400;
  }
  else {
   return 700;
  }
 }
 else {
  return width;
 }
}

function changeViewPort() { //change viewport dynamically by changing the meta 'content' attribute

 if (safari) { // mobile safari will not swap screen.width with screen.height after orientation change
  if (window.orientation == 0) { ot="portrait"; } else { ot="landscape"; }
 }
 else { // other broswers will have height and width swapped
  if (screen.width<screen.height) { ot="portrait"; } else { ot="landscape"; }
 }

 var mobileWidth = getMobileWidth();
 alert("setting the width of "+mobileWidth);
 alert("screen in "+ot+" mode w:"+screen.width+" h:"+screen.height+" -->"+window.orientation);

 if (mobile) {
  var vp = document.getElementById('vp');
  vp.setAttribute('content','width='+mobileWidth+', initial-scale=1.0');
 }
}

</script>

</head>

<body bgcolor=orange onorientationchange="changeViewPort()">

<table width=100% height=100% align=center valign=middle>
<tr><td width=100% height=100% align=center valign=middle style="font-family: Lucida Sans, Lucida Sans Unicode, Helvetica, Arial, sans-serif;">Under Construction</td></tr>
</table>

</body>

</html>


Please note the meta tag has been given an ID (id="vp") so that it can be modified when necessary. onorientationchange is used instead of "onresize" as "onresize" will make give a lots of false signal even when the address bar in mobile browsers shows up or hides.

Read More »

Tuesday, April 5, 2016

DIV mask layer not fully covered on top when there is a scroll bar

It's common to create a "mask" layer on top of the page in order to display photos, pop-up messages, etc.

I used to use the "absolute" positioning to do the job under I lately discovered the so called "masked" will move if there is a scroll bar (when shrinking the window's size).

This problem can be easily solved by just setting the DIV to "fixed" position.

Another problem solved! But wait a minute. This solution doesn't work in IE! Let me see if there is a workaround for this...
Read More »

Best Way to Round Up Numbers Using Javascript

I previously found several solutions to round up (float) numbers to closest two decimal places. Some are using complicated function with sofisticated codes but I find this one-liner quite effective and efficient:

Math.round(num*100)/100; // for two decimal places
Math.round(num*1000)/1000; // for three decimal places
.
.

I appreciate the author who did this and sorry for forgetting where I get it from.
Read More »

Wednesday, March 16, 2016

Login with Facebook using PHP with v5 SDK

It has been a long time since my last post about Facebook. Many things have changed since. This time I want to talk about the new version of Login PHP SDK for Facebook.

The latest version of SDK can be found here.

I think I can skip to codes directly as all the steps to install the SDK and obtain the app_id and app_secret can be easily found in the internet. But I need to point out the errors you may see if something goes wrong. If you see the following error:

Parse error: syntax error, unexpected '[', expecting ')' in ...

You need a PHP 5.4 or higher version to avoid this error.

Instead, if you see this:

Cross-site request forgery validation failed. The "state" param from the URL and session do not match.

It means your app_id and app_secret are not registered to run in the current domain.

Facebook required us to run the login authorization process in two parts: the login link page and the call-back page. The login page will produce a link with new access token to comply with OAuth 2.0 flow. The next page is to process the call-back from Facebook with valid access token so as to do anything with the verified login such as accessing the ID or email address.

As my philosophy is always to make things short and simple as programmers will not like anything too windy, I combined the two parts into one PHP script. Here is the hybrid script:

<?php

session_start();

require_once __DIR__ . '/facebookV5/autoload.php'; // Please point to your facebook SDK autoload.php

$fb = new Facebook\Facebook([
  'app_id' => 'Your App ID',
  'app_secret' => 'Your App Secret',
  'default_graph_version' => 'v2.5',
]);



if (!isset($_GET['code'])) { // If it is a callback, you will get 'code' as query string.

  $helper = $fb->getRedirectLoginHelper();

  $myURL = '{Your Login URL}'; // The URL to this very script such as http://yourdomainname.com/this_hybrid_login_script.php
  $permissions = ['email']; // Optional permissions
  $loginUrl = $helper->getLoginUrl($myURL, $permissions);

  //header( 'Location: ' . htmlspecialchars($loginUrl) ); PLEASE DO USE REDIRECT WITH PHP HEADER! Somehow it doesn't work well with Facebook OAuth 2.0 flow
  echo("<meta http-equiv='refresh' content=\"0;URL='". htmlspecialchars($loginUrl) ."'\" />");
  exit;
}
else { // This is the call-back section:

  $helper = $fb->getRedirectLoginHelper();
  try {
    $accessToken = $helper->getAccessToken();
  } catch( Facebook\Exceptions\FacebookSDKException $e ) {
    echo $e->getMessage();
    exit;
  }

  if (isset($accessToken)) {
    $_SESSION['facebook_access_token'] = ( string ) $accessToken;

    $fb->setDefaultAccessToken($accessToken);

    try {
      $response = $fb->get('/me?fields=email');
      $userNode = $response->getGraphUser();
    } catch(Facebook\Exceptions\FacebookResponseException $e) {
      echo 'Graph returned an error: ' . $e->getMessage();
      exit;
    } catch(Facebook\Exceptions\FacebookSDKException $e) {
      echo 'Facebook SDK returned an error: ' . $e->getMessage();
      exit;
    }

    $me = $response->getGraphUser();
    echo "Your Facebook Email: ".$me->getProperty('email');

    // You now can use the email for the rest of the login process

    exit;
  }
  else if ( $helper->getError() ) {

    // Facebook Login Error

    echo( $helper->getError()."<br>" );
    echo( $helper->getErrorCode()."<br>" );
    echo( $helper->getErrorReason()."<br>" );
    echo( $helper->getErrorDescription()."<br>" );
    exit;
  }

  echo("Access Token cannot be obtained.");
  // You need to debug if you see this as it shouldn't reach here.
  exit;
}

?>


This is a 2-in-1 script. I use the query string 'code' as a signal to decide where it is a call-back from Facebook or it is the first-run before linking to Facebook. If everything goes well and your browser has not run this PHP code before, you will encounter a page where Facebook will ask for your permission to run this PHP app. Here is an example of how it looks like:



After continuing this authorization process, you will not see this page again unless you change the app_id and app_secret. Enjoy logging in with Facebook!

Read More »

Monday, March 7, 2016

Limit a DIV to Certain Scroll Height with Javascript

This is very popular nowadays. You can see major websites around the internet are having this feature. Why? Important information will not get left out if the web page is scrolled down a lot. This can improve the navigation experience of the website substantially. So how is it done? You may need to know how to fix a DIV before you can fully understand this post. Here are some of my earlier posts related to this subject:

http://webtrick101.blogspot.my/2015/11/fixing-several-divs-at-same-time-for.html
http://webtrick101.blogspot.my/2015/11/fix- div-on-top-of-page-only-after.html
http://webtrick101.blogspot.my/2015/11/fix-position-of-div-at-bottom-of-page.html

Here are the codes for this post:

<!DOCTYPE HTML>
<html>
<style type="text/css">

#fixbot {
bottom:0px;
position: fixed;
}

#fixright {
right:0px;
position: absolute;
}

#fixtop {
top:0px;
position: fixed;
}

</style>

<script>

var offset;

window.onscroll = function() {

 if (typeof(window.pageYOffset) == 'number') {
  offset = window.pageYOffset;
 }
 else if (document.documentElement) {
  offset = document.documentElement.scrollTop;
 }
 else if (document.body) {
  offset = document.body.scrollTop;
 }
 if (offset > 170) {
  document.getElementById('fixright').style.position = 'fixed';
  document.getElementById('fixright').style.top = '170px';
 }
 else {
  document.getElementById('fixright').style.position = 'absolute';
  document.getElementById('fixright').style.top = '50%';
 }
 document.getElementById('notice').innerHTML = offset;
}

</script>

<body bgcolor="#aabbcc" marginheight=0 marginwidth=0 leftmargin=0 topmargin=0 rightmargin=0 bottommargin=0 onload="window.scrollTo(0,0);">

<div id="fixbot" style="border:0px solid #333; width:100%; height:50px; background-color:#ddd; text-align:center; padding:0px; ">
<p>Hello I am at the bottom!</p>
</div>

<div id="fixright" style="border:0px; width:100px; height:200px; text-align:center; padding:0px; top: 50%; margin-top: -100px; background-color:#cba;">
<table width=100% height=100%><tr><td valign=middle><p>Right!</p></td></tr></table>
</div>

<div id="fixtop" style="border:0px solid #333; width:100%; height:70px; background-color:#ddd; text-align:center; padding:0px; "> <p>Hello I am at the top! <span id="notice"></span></p>
</div>

<table width="95%" align=center><tr><td>
<br>line 1<br>line 2<br>line 3<br>line 4<br>line 5<br>line 6<br>line 7<br>line 8<br>line 9<br>line 10 <br>line 11<br>line 12<br>line 13<br>line 14<br>line 15<br>line 16<br>line 17<br>line 18<br>line 19<br>line 20 <br>line 21<br>line 22<br>line 23<br>line 24<br>line 25<br>line 26<br>line 27<br>line 28<br>line 29<br>line 30 <br>line 31<br>line 32<br>line 33<br>line 34<br>line 35<br>line 36<br>line 37<br>line 38<br>line 39<br>line 40 <br>line 41<br>line 42<br>line 43<br>line 44<br>line 45<br>line 46<br>line 47<br>line 48<br>line 49<br>line 50 <br>line 51<br>line 52<br>line 53<br>line 54<br>line 55<br>line 56<br>line 57<br>line 58<br>line 59<br>line 60 <br>line 61<br>line 62<br>line 63<br>line 64<br>line 65<br>line 66<br>line 67<br>line 68<br>line 69<br>line 70 </td></tr></table>

<script>
setTimeout(function() {window.scrollTo(0, 0);},100); // To make sure when the page is reloaded, the scroll is back to 0
document.getElementById('fixright').style.top = '50%';

</script>

</body>
</html>




In order to position a DIV on the middle of the right hand side, I prepare the DIV to be always 50% of the total height and the - 100px margin (derived from half of the total height of the DIV which is 200px in this case). In this example, I want to fix the right hand DIV to be exactly 70x from the top of the page. I need to let the Javascript to do the job for me by checking the mouse scroll offset. The magic 170px limit can be obtained from adding the half of the total height of the DIV with the target height limit.



The Javascript will detect the scroll offset if it crosses the 170px marking I set. If it is more than the 170px limit, fix the DIV. If it is less, let it scroll as it should be but maintain the 50% position relative to the viewable height of the website window.



One thing to pay attention is when the page is reloaded, the scroll has to go back to 0 or the calibration of the mechanism of these will be off. If this is not desired, one can consider resorting to cookie to track the relative position of the DIV and scroll offset. This is a head start to such new web feature. More complex feature can still be incorporated into these codes such as managing a very long (high) DIV. Enjoy!

Here is the animated demonstration of this example:



Read More »

Wednesday, February 24, 2016

Good Looking HTML Table Style


Creating a good looking HTML table sounds easy but when it comes to actual execution, it is not as easy as it seems. Consider the following most basic HTML textbook codes for a 3x3 HTML table:

<table border=1>
<tr><td>Apple</td><td>Book</td><td>Car</td></tr>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td></tr>
</table>

Here is how it looks:



This basic table looks unprofessional at the first glance. How about making it with less or thinner border?


<table border=0 cellspacing=0 cellpadding=0>

<tr><td style="border:1px solid #aaa">Apple</td><td style="border:1px solid #aaa">Book</td><td style="border:1px solid #aaa">Car</td></tr>
<tr><td style="border:1px solid #aaa">1</td><td style="border:1px solid #aaa">2</td><td style="border:1px solid #aaa">3</td></tr>
<tr><td style="border:1px solid #aaa">4</td><td style="border:1px solid #aaa">5</td><td style="border:1px solid #aaa">6</td></tr>

</table>

Here it the screen capture of how it looks again:



By disabling the border for entire table and enabling border styling for each individual cell (highlighted in green), the border looks thinner now. But the problem now is the different thickness for the lines. The lines within the box seems thicker than those on the far out. This is due to the double border problem. Those with thicker line came from the neighboring cell borders. Now the next example will demonstrate how to eliminate the redundant lines using CSS:

<table border=0 cellspacing=0 cellpadding=0 style="border-collapse: collapse;">

<tr><td style="border:1px solid #aaa">Apple</td><td style="border:1px solid #aaa">Book</td><td style="border:1px solid #aaa">Car</td></tr>
<tr><td style="border:1px solid #aaa">1</td><td style="border:1px solid #aaa">2</td><td style="border:1px solid #aaa">3</td></tr>
<tr><td style="border:1px solid #aaa">4</td><td style="border:1px solid #aaa">5</td><td style="border:1px solid #aaa">6</td></tr>

</table>

Finally, this looks good:



Setting CSS border-collapse property to collapse now solved the problem. The problem now is the huge number of codes just for a simple 3x3 table. The codes will look complicated when it comes to large table. Now the CSS styling comes into play to simply the coding:

<html>
<style type="text/css">
.s1 {font-family: arial; font-size: 13px; padding: 12px; border-collapse: collapse; }
.s1 td { padding: 5px; border: 1px solid #aaa; text-align: center; }
</style>


<body>

<table class=s1>
<tr><td>Apple</td><td>Book</td><td>Car</td></tr>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td></tr>
</table>

</body>
</html>

It now looks more prefessional:



Now the table looks much better. Please note that those in green are the extra CSS styles to apply spacing, alignment and font to the table. With these extra settings, the table looks even better! Now you have it, enjoy!
Read More »

Thursday, December 31, 2015

Problem Installing phpBB 3.1 Forum on IIS7 Machine


Anyone having this problem? I tried to install this latest phpBB free web forum into my Windows 7 IIS7 PC but I get this error page:



I then download the earlier version which is 3.0 by clicking on a small button on upper right corner:



After running 3.0 version in the localhost, it works fine:



Anyone having this problem on IIS7 machine before? Maybe switching back to older version is the only solution to this?

Read More »