The Curly Braces Programming and Life.

Handling JSON request in PHP

I’ve been working with PHP and jQuery AJAX quite a bit lately. Along with sending form data to PHP page through AJAX, I’ve written restful web services in PHP that receive data in JSON format.

In general when you are sending data through jQuery AJAX to PHP, you don’t have to specify a contentType. Depending on your type ‘GET’ or ‘POST’, PHP will nicely wrap your content into either the $_POST or $_GET global arrays. When you don’t specify a contentType the default contentType is taken as application/x-www-form-urlencoded; charset=UTF-8’.

Following is the request headers from an AJAX call without contentType specified,

GET /ajax-php/api.php?firstname=Abijeet&lastname=Patro HTTP/1.1  
Host: localhost:8081  
Connection: keep-alive  
Cache-Control: no-cache Pragma: no-cache  
Accept: */*  
X-Requested-With: XMLHttpRequest  
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36  
Content-Type: application/x-www-form-urlencoded; charset=UTF-8  
Referer:http://localhost:8081/ajax-php/index.php  
Accept-Encoding: gzip,deflate,sdch  
Accept-Language: en-US,en;q=0.8,fr;q=0.6  

To further test this, I set up the following PHP code on my server,

$get=$_GET;
$post=$_POST;
$app_json=json_decode(file_get_contents('php://input');
$response=array();
$response['GET']=$get;
$response['POST']=$post;
$response['JSON']=$app_json;
echo json_encode($response);  
die();  

The response that for the above request case was,

{"GET":{"firstname":"Abijeet","lastname":"Patro"},"POST":[],"JSON":null}

If we put the jQuery AJAX type property as ‘POST’ we will have the following request header,

POST /ajax-php/api.php HTTP/1.1  
Host: localhost:8081  
Connection: keep-alive  
Content-Length: 32  
Cache-Control: no-cache  
Pragma: no-cache  
Origin: http://localhost:8081  
X-Requested-With: XMLHttpRequest  
Content-Type: application/x-www-form-urlencoded;  
charset=UTF-8  
Accept: */*  
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36  
Referer: http://localhost:8081/ajax-php/index.php  
Accept-Encoding: gzip,deflate,sdch  
Accept-Language: en-US,en;q=0.8,fr;q=0.6  

Nothing much changes. The action is specified as POST and the data is no longer a part of the request header. The response from the server is following,

{"GET":[],"POST":{"firstname":"Abijeet","lastname":"Patro"},"JSON":null}

Obviously, PHP has no issues parsing content of type - application/x-www-form-urlencoded; charset=UTF-8. As soon as it sees that contentType, it checks the action and packs the data nicely into either $_GET or $_POST.

Let’s now talk about JSON data. In general, restful web services accept data of type JSON. When sending data via JSON the contentType for jQuery AJAX is application/json; charset=UTF-8

This is the request header,

POST /ajax-php/api.php HTTP/1.1  
Host: localhost:8081  
Connection: keep-alive  
Content-Length: 42  
Cache-Control: no-cache  
Pragma: no-cache  
Origin: http://localhost:8081  
X-Requested-With: XMLHttpRequest  
Content-Type: application/json; charset=UTF-8  
Accept: */*  
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36  
Referer: http://localhost:8081/ajax-php/index.php  
Accept-Encoding: gzip,deflate,sdch  
Accept-Language: en-US,en;q=0.8,fr;q=0.6  

When PHP receives this data and looks at the content type, it’s not quite sure how to process it, so it leaves it alone. In this case the action – ‘POST’ or ‘GET’ doesn’t matter. You’ll notice that $_POST or $_GET both, are empty arrays. Now, it’s up to you to read this data and parse it.

$app_json=json_decode(file_get_contents('php://input'));

The code above, reads the data from PHP’s input stream. Since we have passed a JSON string, we decode it, which converts it to a PHP array and stores it in $app_json. If the data you send is not in a correct JSON format, $app_json will have false.

When we echo our response, we get the following on the client side,

{"GET":[],"POST":[],"JSON":{"firstname":"Abijeet","lastname":"Patro"}}

I set up a small project to illustrate what has been written here. You can find it over on my github page.

get_results PHP function not working on CentOS

There are instances where the PHP function - get_results will not work on CentOS (this maybe the case with other Linux based operating systems as well). I faced this issue while deploying a project on CentOS which was originally developed on Windows. All my INSERT, UPDATE and DELETE database statements were working properly, but bulk SELECTstatements had issues. After closer inspection I was able to narrow it down to get_results function.

While reading the documentation, I came across this on the get_results documentation page -

MySQL Native Driver Only  
Available only with mysqlnd.  

Using this post on StackOverflow I was able to determine if mysqlnd driver was actually installed and as expected it wasn't.

Posting php code from the StackOverflow post -

$mysqlnd=function_exists('mysqli_fetch_all');
if($mysqlnd) {  
   echo 'mysqlnd enabled!';
}

Here are the steps used to get the mysqlnd driver working on CentOS,

// First remove the existing MySQL driver<br></br>
yum --enablerepo=remi,remi-test remove php-mysql

// Then go ahead and install mysqlnd<br></br>
yum --enablerepo=remi,remi-test install php-mysqlnd

// Restart httpd<br></br>
/sbin/service httpd restart

// If you have phpMyAdmin, re-install it so that it uses the new MySQL driver
yum remove phpMyAdmin  
yum install phpMyAdmin  

Once the mysqlnd driver had been installed I had no issues while using the get_results function.

Tree view based file explorer for the web using jQuery.

This post assumes that the reader has a basic understanding of PHP, jQuery and jQuery $.post

Recently I had to implement a windows-esque tree view based file explorer for one of my projects at work. I ended up using this wonderful jQuery plugin to help me. In this blog I'll be going through some basic code to get it working using PHP on the server side.

To whet your appetite, here's what we'll be achieving in this blog post - A complete tree view based file explorer that feeds from a folder on the server's file system.

File tree view

So let's get started!

To be able to render a proper tree using the aciTree plugin, we'll need to send JSON from server in the following format -

[
  {
    "id": "folder_1",
    "label": "ThisisFolder1",
    "inode": true,
    "open": false,
    "icon": "folder",
    "branch": [
      {
        "id": "sub-item_x",
        "label": "ThisisFileX",
        "inode": false,
        "icon": "file"
      },
      {
        "...": "..."
      },
      {
        "...": "..."
      }
    ]
  },
  {
    "id": "file_1",
    "label": "ThisisFile1",
    "inode": false,
    "icon": "file"
  },
  {
    "...": "..."
  },
  {
    "...": "..."
  }
]

Here's the list of things that we'll be doing -

  1. Server Side Code
  2. HTML
  3. JavaScript/jQuery code to communicate with the server.
  4. Basic event handling for the aciTree plugin.

1. Server side code

Let's move onto the PHP code. Our job is to read the files from the specified folder and return a JSON structure that resembles what's shown above. If you look closely you'll observe that the JSON above is basically an array of objects of with properties as - id, label, inode, icon, open

The following class is exactly similar to that of the class received via JSON. We'll be returning an array of NodeList objects from the server.

/**
 * Represents each node in the aci tree jquery plugin
 * 
 * @author abijeet
 */
class NodeList {  
    public $id, $label, $inode, $open, $icon, $branch;
    private $openIfBranch;

    /**
     * Constructor for NodeList
     *
     * @param string $label
     *          Label of the node
     * @param boolean $open
     *          If this is a branch, should it be open
     * @param string $icon
     *          Icon for the node
     */
    public function __construct($label, $open, $id, $icon = '') {
        if ($id) {
            $this->id = $id;
        }
        $this->label = basename($label);
        $this->open = false;
        $this->openIfBranch = $open;
        $this->icon = $icon;
        $this->inode = false;
    }

    public function setBranch($branch) {
        $this->branch = $branch;
        $cntBranch = count($branch);
        if ($cntBranch > 0) {
            $this->inode = true;
            $this->label .= ' [' . $cntBranch . ']';
        }
        $this->open = $this->openIfBranch;
    }
}

Now to read the list of files and folders from a location on the server -

/**
 * Function that given a path, returns an array of nodeList
 * This can then be converted to a json format.
 * 
 * @param $path Path
 *            of the folder from which to retrieve
 * @return multitype:NodeList Returns the json tree
 */
function jsonForResTree($path) {  
    $dirArray = getAllFilesAndFolders($path);
    $nodeArray = array ();
    $node = '';
    $cnt = count($dirArray);
    for($i = 0; $i < $cnt; ++ $i) {
        $node = new NodeList($dirArray[$i], false);
        if (is_dir($dirArray[$i])) {
            // Recursion - It's a folder, get the array of nodeList for it.
            $nodeList = jsonForResTree($dirArray[$i]);
            // Add it as branch
            $node->setBranch($nodeList);
        }
        $nodeArray[] = $node;
    }
    return $nodeArray;
}

/**
 * Gets all files and folders from the specified path
 * 
 * @param unknown $path
 *            Path of the folder from where files and folders are to be retrieved
 * @return multitype:
 */
function getAllFilesAndFolders($path) {  
    if (! is_dir($path)) {
        return array ();
    }
    $path = $path . DIRECTORY_SEPARATOR . '*';
    return glob($path, GLOB_NOSORT);
}

Some code to handle the request that we will be making from the client side and then echoing the output in JSON format -

if (! empty($_POST['method'])) {  
    // Do some check before handling the POST data.
    $methodToCall = $_POST['method'];
    ob_clean();
    // Call the method requested from the client side.
    $result = call_user_func($methodToCall);
    die(json_encode($result));
}

/**
 * Function that is call by the JQUERY post.
 * 
 * @return multitype:NodeList
 */
function getJsonTree() {  
    // Folder Path from where we are going to show the tree view.
    $pathToGetAciTree = './cakephp';
    $jsonTree = jsonForResTree($pathToGetAciTree);
    return $jsonTree;
}

Okay so we have the PHP code in place. Next order of things -

  1. Server Side Code
  2. HTML
  3. JavaScript/jQuery code to communicate with the server.
  4. Basic event handling for the aciTree plugin.

2. HTML

The following HTML goes inside the body tag-

<!-- Scripts and CSS to be loaded. This will be avaliable when you download aciTree plugin -->  
<link href="css/aciTree.css" rel="stylesheet" type="text/css" />  
<link href="css/demo.css" rel="stylesheet" type="text/css" /> 

<!-- Loading jQuery -->  
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>  
<!-- Loading the aciTree plugin -->  
<script type="text/javascript" src="js/jquery.aciPlugin.min.js"></script>  
<!-- Loading the aciTree core-->  
<script type="text/javascript" src="js/jquery.aciTree.core.js"></script>  
<!-- Loading the aciTree selectable plugin -->  
<script type="text/javascript" src="js/jquery.aciTree.selectable.js"></script> <!-- The div that will contain the ACI Tree -->  
<div id="fsTree"></div> <button id="btnGetTreeView">Get Tree View</button> <button id="btnRefreshTreeView">Refresh Tree View</button>  
<div id="currStatus"></div>  

Next, the JavaScript/jQuery to get the aciTree plugin working. This should be put inside the document's ready handler -

3. jQuery code to communicate with the server

$currStatus = $('#currStatus');
// Makes the ajax call and fetches the json for the resource tree.
$('#btnGetTreeView').click(function() {
  $("#fsTree").aciTree({
    ajax: {
      type: 'POST',
      url: 'index.php',
      data: {
        // Notice that this is the method name that
        // we wish to call on the server side.
        'method': 'getJsonTree'
      }
    }
  });
});

// Refreshing the tree view - Destroy and recreate
$('#btnRefreshTreeView').click(function() {
  var api = $('#fsTree').aciTree('api');
  api.unload(null, {
    success: function() {
      this.ajaxLoad(null);
      // Triggering the click handler of the Get Tree View button.
      // This will make the ajax call again and bind the tree...
      $('#btnGetTreeView').trigger('click');
      $currStatus.text('');
    }
  });
});

4. Event handling for the aciTree plugin

And finally a simple event handler for the aciTree that is triggered whenever a node in the tree is selected -

// ACI Tree - event handler.
$('#fsTree').on('acitree', function(event, aciApi, item, eventName, opt) {
  switch (eventName) {
    case 'focused':
    case 'selected':
      // Fired when an item in the tree is selected.
      if (item) {
        $currStatus.text('Selected - ' + item.context.innerText);
      }
  }
});

You can find the whole code here and a working copy of the project here.

My Crunchbang setup

Update 2016-01-16

Development of Crunchbang has now stopped. There are a few community spin-offs available, Bunsen Labs and Crunchbang++. Although most of what's been written here should be applicable to these distributions, it hasn't been tested. I'm now using a netinst version of Debian at home with the i3 window manager, and Bunsen Labs on my office laptop. Both are working well.


For the past year and a half, I've been working primarily on Microsoft's stack – C#.NET, ASP.NET Web Forms, HTML, CSS, JavaScript (jQuery primarily). My company recently started taking up projects on open source software such as PHP, WordPress and Android. This gave me an opportunity to shift to Linux again. I've always been fond of Linux. The ability to customize and fine tune your system to just the way you like it gives me a sense of freedom and power.

Last Friday, I installed Crunchbang. It is a Linux distribution derived from Debian. The purpose of this post is to outline the various steps I followed to get Crunchbang ready for use. I can then refer to this post whenever I'm setting up my system again, or helping someone else set up theirs.

Hardware Configuration

I'll start of with my computer specifications first. This might help people with similar hardware configuration to find a solution to their problems.

Name Configuration
Processor Intel i5-4570 CPU @ 3.20GHz
Motherboard Gigabyte H87M-D3H
RAM 6.00 GB RAM
Video Card MSI HD 7850 Hawk
Monitor(s) Philips 190VW (1440 X 900) Dell S2240L (1920 x 1080)

System Update

Once Crunchbang is installed and you boot up for the first time a handy script starts up that allows you to update your system and installed software. This script can be invoked later on as well by running cb-welcome command on the terminal.

Installing LAMP and Java

Follow the script and install Java and the LAMP stack. It is also possible to install – Git, SVN and drivers for printer.

Installing AMD Proprietary Driver

After the script has finished, it's time to install the graphics driver.

I followed the manual method outlined in this post on the Crunchbang forums. I tried using smxi to do it for me, but I think it was having trouble disabling the default Radeon drivers. Follow the exact steps, and reboot whenever advised.

Setup dual monitors in AMD CCC

Okay, so driver installation is over. It's time to set up dual monitors. By default, after you've installed Crunchbang on a system that has dual monitors and an AMD graphics card, the monitors will duplicate each other. Once you've installed the driver you can change that setting. Fire up the AMD Catalyst Control Center by running amdcccle command on the terminal.

Change the mode to extend the display to two monitors rather than duplicate the display -

Multiple Monitors in AMD CCC

Placing monitors in the correct order (left or right of each other) is as simple as dragging them into place. You can also change the resolution from this screen.

Another problem that people with DELL S2240L and AMD cards will have that the display on the monitor won't re-size to fit the entire screen. The fix for that is  available through CCC -

Dell S2240L Overscan Correction

Note that the CCC makes changes to the xorg.conf file in /etc/X11. If you don't want to make these changes everytime you reinstall Crunchbang, just backup that file.

Installing Logitech Wireless Driver

I have a wireless Logitech keyboard. With the new motherboard the keyboard is not auto detected by Crunchbang. Installing the driver found here and then restarting resolves the issue.

Boot Error : platform-microcode : intel-ucode ... (not found?)

If you are running new Intel hardware, the following error -

platform microcode: firmware: agent aborted loading intel-ucode/06-1a-05 (not found?)

seems to pop up during boot. It's basically harmless, but can be fixed by installing intel-microcode using APT.

Un-install Software

gFTP
Transmission
Gnumeric
VLC Media Player
Abiword

Install Software

Following is a list of software I install after installing #!

Deluge

Torrent client

sudo apt-get install deluge  

Clementine

Music player

sudo apt-get install clementine  

Dropbox

Use existing #! script, under the Openbox menu, Networking tab.

MPlayer

Video player

sudo apt-get install mplayer  

Then change add the following to the ~/.mplayer/config -

#Volume softvol=1 softvol-max=400

This raises the max volume to 400%.

Artha

Dictionary

sudo apt-get install artha  

Google Chrome

Use existing #! script, under the Openbox menu, Networking tab.

Flux

Monitor screen color manager

I know the above line, doesn't make it sound very exciting, but you really should give flux a go.

  • Grab the binary from here. That's the xflux daemon (command line, but for X-Windows).
  • Add the following line to Openbox autostart file to start xflux daemon on system startup.
# l – latitude, g - longitude
xflux -l 17.4 -g 78.5  

Netbeans

Development IDE for PHP

Grab the installer from here

Code::Blocks

C / C++ Editor

Grab the .deb from here

OpenOffice

Grab the .deb installation files from here
Run the following commands one after the other -

sudo dpkg -i *.deb  
cd desktop-integration  
sudo dpkg -i *.deb``  

Customize Startup and Openbox Menu

autostart.sh determines the applications to be run at start-up and menu.xml defines the layout of the Openbox menu.

Here is my current autostart.sh file and here is my menu.xml.

Customize Conky and Tint2

Conky is basically a system monitor software for the X Window System. It can be extend via plugins and can be customized to show things such as weather.

Tint2 is a task-bar designed to be simple and lightweight. Here's my tint2 config file.

My Conky configuration can be found here. The result -

Conky Screenshot

That's it. That's all I do once Crunchbang has been installed. It took me about four hours hours, but with this post as a reference, next time I should be able to reduce that time to about an hour.

Crunchbang is wonderful distribution that is minimalist, fast, stable and extremely customizable. It runs very well on old and new hardware. They have a helpful and friendly community. So, if you are looking for a new Linux distribution to try out, do give Crunchbang a test drive.

  1. List of software that can be installed using APT on !#.

Macro to insert date time in Visual Studio 2010

My current assignment at work has me working through a lot of old code. Code that now needs to be modified to implement new features and remove bugs. While updating or modifying existing code it is very important to insert comments stating  why the modifications were carried out and the date on which they were carried out. Eventually when other developers work on the same piece of software and compare revisions, they shouldn’t be left wondering why a certain modification was made.

Unfortunately, Visual Studio lacks insert date time at current position functionality. But what it does support are Macros, and using those, it’s quite easy to implement that feature ourselves.

Macros  are written in VB.NET. The following VB.NET code can be used to insert the date time at the current caret position -

Sub PrintDateTime()  
    If (Not IsNothing(DTE.ActiveDocument)) Then   
        Dim selection As TextSelection = DTE.ActiveDocument.Selection   
        selection.Insert(DateTime.Now.ToString())   
    EndIf   
EndSub  

The code above creates a module called PrintDateTime.

  1. It first checks if there is an active document, if there, it gets the currently selected text.
  2. It then inserts current date time at the currently selected caret location.

Next step is to place this code in the correct place.

MacrosDateTime

  1. Open up the Macro explorer by pressing ALT + F8.
  2. In the Macro explorer right click on Macros, and click on ‘New Macro Project’.
  3. Give it a name, and once it’s created, it should be visible in the Macro explorer.
  4. Create a new Module under the project and give it a name that relates to what you are doing
  5. Double click on the new Module to open a Macro editor.
  6. Paste the code above in that editor and save the file.

Now that that is done, your Module should be visible under your project. The next thing we have to do is to assign our newly created Macro to a shortcut key, so that we can easily run it whenever we want.

  1. On the file menu, click on Tools > Options
  2. On the window that opens up, in the tree view, go to Environment > Keyboard
  3. In the Show commands containing textbox, type the name of the Module you created earlier and it should show up in the list below the textbox. Select it.
  4. In the Press shortcut keys textbox, press the combination of keys that you want to use whenever you wish to run your Macro.
  5. Make sure Global is selected under Use new shortcut in: and then press the Assign button, followed by OK.

KeyBoardShortcutVS

It’s time to see if what we did works! Open up a document and press the same combination of keys that you used to create the shortcut. Once you do, the date time should be inserted at your current caret position and this should work for any document that you create inside Visual Studio 2010.

Newer Posts Older Posts